blob: 1b918cc4f1e306287f3ddf8aa9c4fc04a2f881a2 [file] [log] [blame]
Tao Baoafaa0a62017-02-27 15:08:36 -08001#!/usr/bin/env python
2
3# Copyright (C) 2017 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17"""
18Validate a given (signed) target_files.zip.
19
Tao Baoba557702018-03-10 20:41:16 -080020It performs the following checks to assert the integrity of the input zip.
21
Tao Baoafaa0a62017-02-27 15:08:36 -080022 - It verifies the file consistency between the ones in IMAGES/system.img (read
23 via IMAGES/system.map) and the ones under unpacked folder of SYSTEM/. The
24 same check also applies to the vendor image if present.
Tao Baoba557702018-03-10 20:41:16 -080025
26 - It verifies the install-recovery script consistency, by comparing the
27 checksums in the script against the ones of IMAGES/{boot,recovery}.img.
28
29 - It verifies the signed Verified Boot related images, for both of Verified
30 Boot 1.0 and 2.0 (aka AVB).
Tao Baoafaa0a62017-02-27 15:08:36 -080031"""
32
Tao Baoba557702018-03-10 20:41:16 -080033import argparse
34import filecmp
Tao Baoafaa0a62017-02-27 15:08:36 -080035import logging
36import os.path
Tianjie Xu9c384d22017-06-20 17:00:55 -070037import re
Tao Baoc63626b2018-03-07 21:40:24 -080038import zipfile
Tao Bao22632cc2019-10-03 23:12:55 -070039from hashlib import sha1
Tao Baoafaa0a62017-02-27 15:08:36 -080040
Tao Baobb20e8c2018-02-01 12:00:19 -080041import common
Tao Bao22632cc2019-10-03 23:12:55 -070042import rangelib
Tao Baoafaa0a62017-02-27 15:08:36 -080043
44
Tao Baob418c302017-08-30 15:54:59 -070045def _ReadFile(file_name, unpacked_name, round_up=False):
46 """Constructs and returns a File object. Rounds up its size if needed."""
Tianjie Xu9c384d22017-06-20 17:00:55 -070047 assert os.path.exists(unpacked_name)
Tao Baoda30cfa2017-12-01 16:19:46 -080048 with open(unpacked_name, 'rb') as f:
Tianjie Xu9c384d22017-06-20 17:00:55 -070049 file_data = f.read()
50 file_size = len(file_data)
51 if round_up:
Tao Baoc765cca2018-01-31 17:32:40 -080052 file_size_rounded_up = common.RoundUpTo4K(file_size)
Tao Bao22632cc2019-10-03 23:12:55 -070053 file_data += b'\0' * (file_size_rounded_up - file_size)
Tao Baob418c302017-08-30 15:54:59 -070054 return common.File(file_name, file_data)
Tianjie Xu9c384d22017-06-20 17:00:55 -070055
56
57def ValidateFileAgainstSha1(input_tmp, file_name, file_path, expected_sha1):
58 """Check if the file has the expected SHA-1."""
59
Tao Baobb20e8c2018-02-01 12:00:19 -080060 logging.info('Validating the SHA-1 of %s', file_name)
Tianjie Xu9c384d22017-06-20 17:00:55 -070061 unpacked_name = os.path.join(input_tmp, file_path)
62 assert os.path.exists(unpacked_name)
Tao Baob418c302017-08-30 15:54:59 -070063 actual_sha1 = _ReadFile(file_name, unpacked_name, False).sha1
Tianjie Xu9c384d22017-06-20 17:00:55 -070064 assert actual_sha1 == expected_sha1, \
65 'SHA-1 mismatches for {}. actual {}, expected {}'.format(
Tao Baobb20e8c2018-02-01 12:00:19 -080066 file_name, actual_sha1, expected_sha1)
Tianjie Xu9c384d22017-06-20 17:00:55 -070067
68
Tao Bao63e2f492018-05-11 23:38:46 -070069def ValidateFileConsistency(input_zip, input_tmp, info_dict):
Tianjie Xu9c384d22017-06-20 17:00:55 -070070 """Compare the files from image files and unpacked folders."""
71
Tao Baoafaa0a62017-02-27 15:08:36 -080072 def CheckAllFiles(which):
73 logging.info('Checking %s image.', which)
Tao Baoc63626b2018-03-07 21:40:24 -080074 # Allow having shared blocks when loading the sparse image, because allowing
75 # that doesn't affect the checks below (we will have all the blocks on file,
76 # unless it's skipped due to the holes).
77 image = common.GetSparseImage(which, input_tmp, input_zip, True)
Tao Baoafaa0a62017-02-27 15:08:36 -080078 prefix = '/' + which
79 for entry in image.file_map:
Tao Baoc765cca2018-01-31 17:32:40 -080080 # Skip entries like '__NONZERO-0'.
Tao Baoafaa0a62017-02-27 15:08:36 -080081 if not entry.startswith(prefix):
82 continue
83
84 # Read the blocks that the file resides. Note that it will contain the
85 # bytes past the file length, which is expected to be padded with '\0's.
86 ranges = image.file_map[entry]
Tao Baoc765cca2018-01-31 17:32:40 -080087
Tao Bao2a20f342018-12-03 15:08:23 -080088 # Use the original RangeSet if applicable, which includes the shared
89 # blocks. And this needs to happen before checking the monotonicity flag.
90 if ranges.extra.get('uses_shared_blocks'):
91 file_ranges = ranges.extra['uses_shared_blocks']
92 else:
93 file_ranges = ranges
94
xunchangc0f77ee2019-02-20 15:03:43 -080095 incomplete = file_ranges.extra.get('incomplete', False)
96 if incomplete:
97 logging.warning('Skipping %s that has incomplete block list', entry)
98 continue
99
Tao Bao22632cc2019-10-03 23:12:55 -0700100 # If the file has non-monotonic ranges, read each range in order.
Tao Bao2a20f342018-12-03 15:08:23 -0800101 if not file_ranges.monotonic:
Tao Bao22632cc2019-10-03 23:12:55 -0700102 h = sha1()
103 for file_range in file_ranges.extra['text_str'].split(' '):
104 for data in image.ReadRangeSet(rangelib.RangeSet(file_range)):
105 h.update(data)
106 blocks_sha1 = h.hexdigest()
107 else:
108 blocks_sha1 = image.RangeSha1(file_ranges)
Tao Baoafaa0a62017-02-27 15:08:36 -0800109
110 # The filename under unpacked directory, such as SYSTEM/bin/sh.
111 unpacked_name = os.path.join(
112 input_tmp, which.upper(), entry[(len(prefix) + 1):])
Tao Baob418c302017-08-30 15:54:59 -0700113 unpacked_file = _ReadFile(entry, unpacked_name, True)
Tao Baob418c302017-08-30 15:54:59 -0700114 file_sha1 = unpacked_file.sha1
Tao Baoafaa0a62017-02-27 15:08:36 -0800115 assert blocks_sha1 == file_sha1, \
116 'file: %s, range: %s, blocks_sha1: %s, file_sha1: %s' % (
Tao Bao2a20f342018-12-03 15:08:23 -0800117 entry, file_ranges, blocks_sha1, file_sha1)
Tao Baoafaa0a62017-02-27 15:08:36 -0800118
119 logging.info('Validating file consistency.')
120
Tao Bao63e2f492018-05-11 23:38:46 -0700121 # TODO(b/79617342): Validate non-sparse images.
122 if info_dict.get('extfs_sparse_flag') != '-s':
123 logging.warning('Skipped due to target using non-sparse images')
124 return
125
Tao Baoafaa0a62017-02-27 15:08:36 -0800126 # Verify IMAGES/system.img.
127 CheckAllFiles('system')
128
129 # Verify IMAGES/vendor.img if applicable.
130 if 'VENDOR/' in input_zip.namelist():
131 CheckAllFiles('vendor')
132
133 # Not checking IMAGES/system_other.img since it doesn't have the map file.
134
135
Tianjie Xu9c384d22017-06-20 17:00:55 -0700136def ValidateInstallRecoveryScript(input_tmp, info_dict):
137 """Validate the SHA-1 embedded in install-recovery.sh.
138
139 install-recovery.sh is written in common.py and has the following format:
140
141 1. full recovery:
142 ...
Tao Bao4948aed2018-07-13 16:11:16 -0700143 if ! applypatch --check type:device:size:sha1; then
Bill Peckhame868aec2019-09-17 17:06:47 -0700144 applypatch --flash /vendor/etc/recovery.img \\
Tao Bao4948aed2018-07-13 16:11:16 -0700145 type:device:size:sha1 && \\
Tianjie Xu9c384d22017-06-20 17:00:55 -0700146 ...
147
148 2. recovery from boot:
149 ...
Tao Bao4948aed2018-07-13 16:11:16 -0700150 if ! applypatch --check type:recovery_device:recovery_size:recovery_sha1; then
151 applypatch [--bonus bonus_args] \\
Bill Peckhame868aec2019-09-17 17:06:47 -0700152 --patch /vendor/recovery-from-boot.p \\
Tao Bao4948aed2018-07-13 16:11:16 -0700153 --source type:boot_device:boot_size:boot_sha1 \\
154 --target type:recovery_device:recovery_size:recovery_sha1 && \\
Tianjie Xu9c384d22017-06-20 17:00:55 -0700155 ...
156
Bill Peckhame868aec2019-09-17 17:06:47 -0700157 For full recovery, we want to calculate the SHA-1 of /vendor/etc/recovery.img
Tianjie Xu9c384d22017-06-20 17:00:55 -0700158 and compare it against the one embedded in the script. While for recovery
159 from boot, we want to check the SHA-1 for both recovery.img and boot.img
160 under IMAGES/.
161 """
162
Bill Peckhame868aec2019-09-17 17:06:47 -0700163 board_uses_vendorimage = info_dict.get("board_uses_vendorimage") == "true"
164
165 if board_uses_vendorimage:
166 script_path = 'VENDOR/bin/install-recovery.sh'
167 recovery_img = 'VENDOR/etc/recovery.img'
168 else:
169 script_path = 'SYSTEM/vendor/bin/install-recovery.sh'
170 recovery_img = 'SYSTEM/vendor/etc/recovery.img'
171
Tianjie Xu9c384d22017-06-20 17:00:55 -0700172 if not os.path.exists(os.path.join(input_tmp, script_path)):
Tao Baobb20e8c2018-02-01 12:00:19 -0800173 logging.info('%s does not exist in input_tmp', script_path)
Tianjie Xu9c384d22017-06-20 17:00:55 -0700174 return
175
Tao Baobb20e8c2018-02-01 12:00:19 -0800176 logging.info('Checking %s', script_path)
Tianjie Xu9c384d22017-06-20 17:00:55 -0700177 with open(os.path.join(input_tmp, script_path), 'r') as script:
178 lines = script.read().strip().split('\n')
Tao Bao4948aed2018-07-13 16:11:16 -0700179 assert len(lines) >= 10
180 check_cmd = re.search(r'if ! applypatch --check (\w+:.+:\w+:\w+);',
Tianjie Xu9c384d22017-06-20 17:00:55 -0700181 lines[1].strip())
Tao Bao4948aed2018-07-13 16:11:16 -0700182 check_partition = check_cmd.group(1)
183 assert len(check_partition.split(':')) == 4
Tianjie Xu9c384d22017-06-20 17:00:55 -0700184
185 full_recovery_image = info_dict.get("full_recovery_image") == "true"
186 if full_recovery_image:
Tao Bao4948aed2018-07-13 16:11:16 -0700187 assert len(lines) == 10, "Invalid line count: {}".format(lines)
Tianjie Xu9c384d22017-06-20 17:00:55 -0700188
Tao Bao4948aed2018-07-13 16:11:16 -0700189 # Expect something like "EMMC:/dev/block/recovery:28:5f9c..62e3".
190 target = re.search(r'--target (.+) &&', lines[4].strip())
191 assert target is not None, \
192 "Failed to parse target line \"{}\"".format(lines[4])
193 flash_partition = target.group(1)
194
195 # Check we have the same recovery target in the check and flash commands.
196 assert check_partition == flash_partition, \
197 "Mismatching targets: {} vs {}".format(check_partition, flash_partition)
198
199 # Validate the SHA-1 of the recovery image.
200 recovery_sha1 = flash_partition.split(':')[3]
201 ValidateFileAgainstSha1(
Bill Peckhame868aec2019-09-17 17:06:47 -0700202 input_tmp, 'recovery.img', recovery_img, recovery_sha1)
Tao Bao4948aed2018-07-13 16:11:16 -0700203 else:
204 assert len(lines) == 11, "Invalid line count: {}".format(lines)
205
206 # --source boot_type:boot_device:boot_size:boot_sha1
207 source = re.search(r'--source (\w+:.+:\w+:\w+) \\', lines[4].strip())
208 assert source is not None, \
209 "Failed to parse source line \"{}\"".format(lines[4])
210
211 source_partition = source.group(1)
212 source_info = source_partition.split(':')
213 assert len(source_info) == 4, \
214 "Invalid source partition: {}".format(source_partition)
Tianjie Xu9c384d22017-06-20 17:00:55 -0700215 ValidateFileAgainstSha1(input_tmp, file_name='boot.img',
Tao Baobb20e8c2018-02-01 12:00:19 -0800216 file_path='IMAGES/boot.img',
Tao Bao4948aed2018-07-13 16:11:16 -0700217 expected_sha1=source_info[3])
Tianjie Xu9c384d22017-06-20 17:00:55 -0700218
Tao Bao4948aed2018-07-13 16:11:16 -0700219 # --target recovery_type:recovery_device:recovery_size:recovery_sha1
220 target = re.search(r'--target (\w+:.+:\w+:\w+) && \\', lines[5].strip())
221 assert target is not None, \
222 "Failed to parse target line \"{}\"".format(lines[5])
223 target_partition = target.group(1)
224
225 # Check we have the same recovery target in the check and patch commands.
226 assert check_partition == target_partition, \
227 "Mismatching targets: {} vs {}".format(
228 check_partition, target_partition)
229
230 recovery_info = target_partition.split(':')
231 assert len(recovery_info) == 4, \
232 "Invalid target partition: {}".format(target_partition)
Tianjie Xu9c384d22017-06-20 17:00:55 -0700233 ValidateFileAgainstSha1(input_tmp, file_name='recovery.img',
Tao Baobb20e8c2018-02-01 12:00:19 -0800234 file_path='IMAGES/recovery.img',
Tao Bao4948aed2018-07-13 16:11:16 -0700235 expected_sha1=recovery_info[3])
Tianjie Xu9c384d22017-06-20 17:00:55 -0700236
Tao Baobb20e8c2018-02-01 12:00:19 -0800237 logging.info('Done checking %s', script_path)
Tianjie Xu9c384d22017-06-20 17:00:55 -0700238
239
Tao Baoba557702018-03-10 20:41:16 -0800240def ValidateVerifiedBootImages(input_tmp, info_dict, options):
241 """Validates the Verified Boot related images.
Tao Baoafaa0a62017-02-27 15:08:36 -0800242
Tao Baoba557702018-03-10 20:41:16 -0800243 For Verified Boot 1.0, it verifies the signatures of the bootable images
244 (boot/recovery etc), as well as the dm-verity metadata in system images
245 (system/vendor/product). For Verified Boot 2.0, it calls avbtool to verify
246 vbmeta.img, which in turn verifies all the descriptors listed in vbmeta.
Tao Baoafaa0a62017-02-27 15:08:36 -0800247
Tao Baoba557702018-03-10 20:41:16 -0800248 Args:
249 input_tmp: The top-level directory of unpacked target-files.zip.
250 info_dict: The loaded info dict.
251 options: A dict that contains the user-supplied public keys to be used for
252 image verification. In particular, 'verity_key' is used to verify the
253 bootable images in VB 1.0, and the vbmeta image in VB 2.0, where
254 applicable. 'verity_key_mincrypt' will be used to verify the system
255 images in VB 1.0.
256
257 Raises:
258 AssertionError: On any verification failure.
259 """
260 # Verified boot 1.0 (images signed with boot_signer and verity_signer).
261 if info_dict.get('boot_signer') == 'true':
262 logging.info('Verifying Verified Boot images...')
263
264 # Verify the boot/recovery images (signed with boot_signer), against the
265 # given X.509 encoded pubkey (or falling back to the one in the info_dict if
266 # none given).
267 verity_key = options['verity_key']
268 if verity_key is None:
269 verity_key = info_dict['verity_key'] + '.x509.pem'
270 for image in ('boot.img', 'recovery.img', 'recovery-two-step.img'):
Tao Bao04808502019-07-25 23:11:41 -0700271 if image == 'recovery-two-step.img':
272 image_path = os.path.join(input_tmp, 'OTA', image)
273 else:
274 image_path = os.path.join(input_tmp, 'IMAGES', image)
Tao Baoba557702018-03-10 20:41:16 -0800275 if not os.path.exists(image_path):
276 continue
277
278 cmd = ['boot_signer', '-verify', image_path, '-certificate', verity_key]
Tao Bao73dd4f42018-10-04 16:25:33 -0700279 proc = common.Run(cmd)
Tao Baoba557702018-03-10 20:41:16 -0800280 stdoutdata, _ = proc.communicate()
281 assert proc.returncode == 0, \
282 'Failed to verify {} with boot_signer:\n{}'.format(image, stdoutdata)
283 logging.info(
284 'Verified %s with boot_signer (key: %s):\n%s', image, verity_key,
285 stdoutdata.rstrip())
286
287 # Verify verity signed system images in Verified Boot 1.0. Note that not using
288 # 'elif' here, since 'boot_signer' and 'verity' are not bundled in VB 1.0.
289 if info_dict.get('verity') == 'true':
Tao Baoc9981932019-09-16 12:10:43 -0700290 # First verify that the verity key is built into the root image (regardless
291 # of system-as-root).
292 verity_key_mincrypt = os.path.join(input_tmp, 'ROOT', 'verity_key')
Tao Baoba557702018-03-10 20:41:16 -0800293 assert os.path.exists(verity_key_mincrypt), 'Missing verity_key'
294
Tao Baoc9981932019-09-16 12:10:43 -0700295 # Verify /verity_key matches the one given via command line, if any.
Tao Baoba557702018-03-10 20:41:16 -0800296 if options['verity_key_mincrypt'] is None:
297 logging.warn(
298 'Skipped checking the content of /verity_key, as the key file not '
299 'provided. Use --verity_key_mincrypt to specify.')
300 else:
301 expected_key = options['verity_key_mincrypt']
302 assert filecmp.cmp(expected_key, verity_key_mincrypt, shallow=False), \
303 "Mismatching mincrypt verity key files"
304 logging.info('Verified the content of /verity_key')
305
Tao Baoc9981932019-09-16 12:10:43 -0700306 # For devices with a separate ramdisk (i.e. non-system-as-root), there must
307 # be a copy in ramdisk.
308 if info_dict.get("system_root_image") != "true":
309 verity_key_ramdisk = os.path.join(
310 input_tmp, 'BOOT', 'RAMDISK', 'verity_key')
311 assert os.path.exists(verity_key_ramdisk), 'Missing verity_key in ramdisk'
312
313 assert filecmp.cmp(
314 verity_key_mincrypt, verity_key_ramdisk, shallow=False), \
315 'Mismatching verity_key files in root and ramdisk'
316 logging.info('Verified the content of /verity_key in ramdisk')
317
Tao Baoba557702018-03-10 20:41:16 -0800318 # Then verify the verity signed system/vendor/product images, against the
319 # verity pubkey in mincrypt format.
320 for image in ('system.img', 'vendor.img', 'product.img'):
321 image_path = os.path.join(input_tmp, 'IMAGES', image)
322
323 # We are not checking if the image is actually enabled via info_dict (e.g.
324 # 'system_verity_block_device=...'). Because it's most likely a bug that
325 # skips signing some of the images in signed target-files.zip, while
326 # having the top-level verity flag enabled.
327 if not os.path.exists(image_path):
328 continue
329
330 cmd = ['verity_verifier', image_path, '-mincrypt', verity_key_mincrypt]
Tao Bao73dd4f42018-10-04 16:25:33 -0700331 proc = common.Run(cmd)
Tao Baoba557702018-03-10 20:41:16 -0800332 stdoutdata, _ = proc.communicate()
333 assert proc.returncode == 0, \
334 'Failed to verify {} with verity_verifier (key: {}):\n{}'.format(
335 image, verity_key_mincrypt, stdoutdata)
336 logging.info(
337 'Verified %s with verity_verifier (key: %s):\n%s', image,
338 verity_key_mincrypt, stdoutdata.rstrip())
339
340 # Handle the case of Verified Boot 2.0 (AVB).
341 if info_dict.get("avb_enable") == "true":
342 logging.info('Verifying Verified Boot 2.0 (AVB) images...')
343
Tao Baoa81d4292019-03-26 12:13:04 -0700344 key = options['verity_key']
345 if key is None:
346 key = info_dict['avb_vbmeta_key_path']
347
348 # avbtool verifies all the images that have descriptors listed in vbmeta.
cfig1aeef722019-09-20 22:45:06 +0800349 # Using `--follow_chain_partitions` so it would additionally verify chained
350 # vbmeta partitions (e.g. vbmeta_system).
Tao Baoa81d4292019-03-26 12:13:04 -0700351 image = os.path.join(input_tmp, 'IMAGES', 'vbmeta.img')
Tao Bao1ac886e2019-06-26 11:58:22 -0700352 cmd = [info_dict['avb_avbtool'], 'verify_image', '--image', image,
Tianjie Xu9bd832a2020-02-06 13:12:56 -0800353 '--follow_chain_partitions']
Tao Baoa81d4292019-03-26 12:13:04 -0700354
355 # Append the args for chained partitions if any.
Tao Bao08c190f2019-06-03 23:07:58 -0700356 for partition in common.AVB_PARTITIONS + common.AVB_VBMETA_PARTITIONS:
Tao Baoa81d4292019-03-26 12:13:04 -0700357 key_name = 'avb_' + partition + '_key_path'
358 if info_dict.get(key_name) is not None:
cfig1aeef722019-09-20 22:45:06 +0800359 if info_dict.get('ab_update') != 'true' and partition == 'recovery':
360 continue
361
Tao Bao08c190f2019-06-03 23:07:58 -0700362 # Use the key file from command line if specified; otherwise fall back
363 # to the one in info dict.
364 key_file = options.get(key_name, info_dict[key_name])
Tao Baoa81d4292019-03-26 12:13:04 -0700365 chained_partition_arg = common.GetAvbChainedPartitionArg(
Tao Bao08c190f2019-06-03 23:07:58 -0700366 partition, info_dict, key_file)
cfig1aeef722019-09-20 22:45:06 +0800367 cmd.extend(['--expected_chain_partition', chained_partition_arg])
Tao Baoa81d4292019-03-26 12:13:04 -0700368
369 proc = common.Run(cmd)
370 stdoutdata, _ = proc.communicate()
371 assert proc.returncode == 0, \
372 'Failed to verify {} with avbtool (key: {}):\n{}'.format(
373 image, key, stdoutdata)
374
375 logging.info(
376 'Verified %s with avbtool (key: %s):\n%s', image, key,
377 stdoutdata.rstrip())
Tao Baoba557702018-03-10 20:41:16 -0800378
cfig1aeef722019-09-20 22:45:06 +0800379 # avbtool verifies recovery image for non-A/B devices.
380 if (info_dict.get('ab_update') != 'true' and
381 info_dict.get('no_recovery') != 'true'):
382 image = os.path.join(input_tmp, 'IMAGES', 'recovery.img')
383 key = info_dict['avb_recovery_key_path']
384 cmd = [info_dict['avb_avbtool'], 'verify_image', '--image', image,
385 '--key', key]
386 proc = common.Run(cmd)
387 stdoutdata, _ = proc.communicate()
388 assert proc.returncode == 0, \
389 'Failed to verify {} with avbtool (key: {}):\n{}'.format(
390 image, key, stdoutdata)
391 logging.info(
392 'Verified %s with avbtool (key: %s):\n%s', image, key,
393 stdoutdata.rstrip())
394
Tao Baoba557702018-03-10 20:41:16 -0800395
396def main():
397 parser = argparse.ArgumentParser(
398 description=__doc__,
399 formatter_class=argparse.RawDescriptionHelpFormatter)
400 parser.add_argument(
401 'target_files',
402 help='the input target_files.zip to be validated')
403 parser.add_argument(
404 '--verity_key',
405 help='the verity public key to verify the bootable images (Verified '
Tao Bao02a08592018-07-22 12:40:45 -0700406 'Boot 1.0), or the vbmeta image (Verified Boot 2.0, aka AVB), where '
Tao Baoba557702018-03-10 20:41:16 -0800407 'applicable')
Tao Bao08c190f2019-06-03 23:07:58 -0700408 for partition in common.AVB_PARTITIONS + common.AVB_VBMETA_PARTITIONS:
Tao Bao02a08592018-07-22 12:40:45 -0700409 parser.add_argument(
410 '--avb_' + partition + '_key_path',
411 help='the public or private key in PEM format to verify AVB chained '
412 'partition of {}'.format(partition))
Tao Baoba557702018-03-10 20:41:16 -0800413 parser.add_argument(
414 '--verity_key_mincrypt',
415 help='the verity public key in mincrypt format to verify the system '
416 'images, if target using Verified Boot 1.0')
417 args = parser.parse_args()
418
419 # Unprovided args will have 'None' as the value.
420 options = vars(args)
Tao Baoafaa0a62017-02-27 15:08:36 -0800421
422 logging_format = '%(asctime)s - %(filename)s - %(levelname)-8s: %(message)s'
423 date_format = '%Y/%m/%d %H:%M:%S'
424 logging.basicConfig(level=logging.INFO, format=logging_format,
425 datefmt=date_format)
426
Tao Baoba557702018-03-10 20:41:16 -0800427 logging.info("Unzipping the input target_files.zip: %s", args.target_files)
428 input_tmp = common.UnzipTemp(args.target_files)
Tao Baoafaa0a62017-02-27 15:08:36 -0800429
Tianjie Xu9c384d22017-06-20 17:00:55 -0700430 info_dict = common.LoadInfoDict(input_tmp)
Tao Bao63e2f492018-05-11 23:38:46 -0700431 with zipfile.ZipFile(args.target_files, 'r') as input_zip:
432 ValidateFileConsistency(input_zip, input_tmp, info_dict)
433
Tianjie Xu9c384d22017-06-20 17:00:55 -0700434 ValidateInstallRecoveryScript(input_tmp, info_dict)
435
Tao Baoba557702018-03-10 20:41:16 -0800436 ValidateVerifiedBootImages(input_tmp, info_dict, options)
437
Tao Baoafaa0a62017-02-27 15:08:36 -0800438 # TODO: Check if the OTA keys have been properly updated (the ones on /system,
439 # in recovery image).
440
Tao Baoafaa0a62017-02-27 15:08:36 -0800441 logging.info("Done.")
442
443
444if __name__ == '__main__':
445 try:
Tao Baoba557702018-03-10 20:41:16 -0800446 main()
Tao Baoafaa0a62017-02-27 15:08:36 -0800447 finally:
448 common.Cleanup()