xref: /aosp_15_r20/build/make/tools/releasetools/validate_target_files.py (revision 9e94795a3d4ef5c1d47486f9a02bb378756cea8a)
1*9e94795aSAndroid Build Coastguard Worker#!/usr/bin/env python
2*9e94795aSAndroid Build Coastguard Worker
3*9e94795aSAndroid Build Coastguard Worker# Copyright (C) 2017 The Android Open Source Project
4*9e94795aSAndroid Build Coastguard Worker#
5*9e94795aSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
6*9e94795aSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
7*9e94795aSAndroid Build Coastguard Worker# You may obtain a copy of the License at
8*9e94795aSAndroid Build Coastguard Worker#
9*9e94795aSAndroid Build Coastguard Worker#      http://www.apache.org/licenses/LICENSE-2.0
10*9e94795aSAndroid Build Coastguard Worker#
11*9e94795aSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
12*9e94795aSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
13*9e94795aSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*9e94795aSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
15*9e94795aSAndroid Build Coastguard Worker# limitations under the License.
16*9e94795aSAndroid Build Coastguard Worker
17*9e94795aSAndroid Build Coastguard Worker"""
18*9e94795aSAndroid Build Coastguard WorkerValidate a given (signed) target_files.zip.
19*9e94795aSAndroid Build Coastguard Worker
20*9e94795aSAndroid Build Coastguard WorkerIt performs the following checks to assert the integrity of the input zip.
21*9e94795aSAndroid Build Coastguard Worker
22*9e94795aSAndroid Build Coastguard Worker - It verifies the file consistency between the ones in IMAGES/system.img (read
23*9e94795aSAndroid Build Coastguard Worker   via IMAGES/system.map) and the ones under unpacked folder of SYSTEM/. The
24*9e94795aSAndroid Build Coastguard Worker   same check also applies to the vendor image if present.
25*9e94795aSAndroid Build Coastguard Worker
26*9e94795aSAndroid Build Coastguard Worker - It verifies the install-recovery script consistency, by comparing the
27*9e94795aSAndroid Build Coastguard Worker   checksums in the script against the ones of IMAGES/{boot,recovery}.img.
28*9e94795aSAndroid Build Coastguard Worker
29*9e94795aSAndroid Build Coastguard Worker - It verifies the signed Verified Boot related images, for both of Verified
30*9e94795aSAndroid Build Coastguard Worker   Boot 1.0 and 2.0 (aka AVB).
31*9e94795aSAndroid Build Coastguard Worker"""
32*9e94795aSAndroid Build Coastguard Worker
33*9e94795aSAndroid Build Coastguard Workerimport argparse
34*9e94795aSAndroid Build Coastguard Workerimport filecmp
35*9e94795aSAndroid Build Coastguard Workerimport logging
36*9e94795aSAndroid Build Coastguard Workerimport os.path
37*9e94795aSAndroid Build Coastguard Workerimport re
38*9e94795aSAndroid Build Coastguard Workerimport zipfile
39*9e94795aSAndroid Build Coastguard Worker
40*9e94795aSAndroid Build Coastguard Workerfrom hashlib import sha1
41*9e94795aSAndroid Build Coastguard Workerfrom common import IsSparseImage
42*9e94795aSAndroid Build Coastguard Worker
43*9e94795aSAndroid Build Coastguard Workerimport common
44*9e94795aSAndroid Build Coastguard Workerimport rangelib
45*9e94795aSAndroid Build Coastguard Worker
46*9e94795aSAndroid Build Coastguard Worker
47*9e94795aSAndroid Build Coastguard Workerdef _ReadFile(file_name, unpacked_name, round_up=False):
48*9e94795aSAndroid Build Coastguard Worker  """Constructs and returns a File object. Rounds up its size if needed."""
49*9e94795aSAndroid Build Coastguard Worker  assert os.path.exists(unpacked_name)
50*9e94795aSAndroid Build Coastguard Worker  with open(unpacked_name, 'rb') as f:
51*9e94795aSAndroid Build Coastguard Worker    file_data = f.read()
52*9e94795aSAndroid Build Coastguard Worker  file_size = len(file_data)
53*9e94795aSAndroid Build Coastguard Worker  if round_up:
54*9e94795aSAndroid Build Coastguard Worker    file_size_rounded_up = common.RoundUpTo4K(file_size)
55*9e94795aSAndroid Build Coastguard Worker    file_data += b'\0' * (file_size_rounded_up - file_size)
56*9e94795aSAndroid Build Coastguard Worker  return common.File(file_name, file_data)
57*9e94795aSAndroid Build Coastguard Worker
58*9e94795aSAndroid Build Coastguard Worker
59*9e94795aSAndroid Build Coastguard Workerdef ValidateFileAgainstSha1(input_tmp, file_name, file_path, expected_sha1):
60*9e94795aSAndroid Build Coastguard Worker  """Check if the file has the expected SHA-1."""
61*9e94795aSAndroid Build Coastguard Worker
62*9e94795aSAndroid Build Coastguard Worker  logging.info('Validating the SHA-1 of %s', file_name)
63*9e94795aSAndroid Build Coastguard Worker  unpacked_name = os.path.join(input_tmp, file_path)
64*9e94795aSAndroid Build Coastguard Worker  assert os.path.exists(unpacked_name)
65*9e94795aSAndroid Build Coastguard Worker  actual_sha1 = _ReadFile(file_name, unpacked_name, False).sha1
66*9e94795aSAndroid Build Coastguard Worker  assert actual_sha1 == expected_sha1, \
67*9e94795aSAndroid Build Coastguard Worker      'SHA-1 mismatches for {}. actual {}, expected {}'.format(
68*9e94795aSAndroid Build Coastguard Worker          file_name, actual_sha1, expected_sha1)
69*9e94795aSAndroid Build Coastguard Worker
70*9e94795aSAndroid Build Coastguard Worker
71*9e94795aSAndroid Build Coastguard Workerdef ValidateFileConsistency(input_zip, input_tmp, info_dict):
72*9e94795aSAndroid Build Coastguard Worker  """Compare the files from image files and unpacked folders."""
73*9e94795aSAndroid Build Coastguard Worker
74*9e94795aSAndroid Build Coastguard Worker  def CheckAllFiles(which):
75*9e94795aSAndroid Build Coastguard Worker    logging.info('Checking %s image.', which)
76*9e94795aSAndroid Build Coastguard Worker    path = os.path.join(input_tmp, "IMAGES", which + ".img")
77*9e94795aSAndroid Build Coastguard Worker    if not IsSparseImage(path):
78*9e94795aSAndroid Build Coastguard Worker      logging.info("%s is non-sparse image", which)
79*9e94795aSAndroid Build Coastguard Worker      image = common.GetNonSparseImage(which, input_tmp)
80*9e94795aSAndroid Build Coastguard Worker    else:
81*9e94795aSAndroid Build Coastguard Worker      logging.info("%s is sparse image", which)
82*9e94795aSAndroid Build Coastguard Worker      # Allow having shared blocks when loading the sparse image, because allowing
83*9e94795aSAndroid Build Coastguard Worker      # that doesn't affect the checks below (we will have all the blocks on file,
84*9e94795aSAndroid Build Coastguard Worker      # unless it's skipped due to the holes).
85*9e94795aSAndroid Build Coastguard Worker      image = common.GetSparseImage(which, input_tmp, input_zip, True)
86*9e94795aSAndroid Build Coastguard Worker    prefix = '/' + which
87*9e94795aSAndroid Build Coastguard Worker    for entry in image.file_map:
88*9e94795aSAndroid Build Coastguard Worker      # Skip entries like '__NONZERO-0'.
89*9e94795aSAndroid Build Coastguard Worker      if not entry.startswith(prefix):
90*9e94795aSAndroid Build Coastguard Worker        continue
91*9e94795aSAndroid Build Coastguard Worker
92*9e94795aSAndroid Build Coastguard Worker      # Read the blocks that the file resides. Note that it will contain the
93*9e94795aSAndroid Build Coastguard Worker      # bytes past the file length, which is expected to be padded with '\0's.
94*9e94795aSAndroid Build Coastguard Worker      ranges = image.file_map[entry]
95*9e94795aSAndroid Build Coastguard Worker
96*9e94795aSAndroid Build Coastguard Worker      # Use the original RangeSet if applicable, which includes the shared
97*9e94795aSAndroid Build Coastguard Worker      # blocks. And this needs to happen before checking the monotonicity flag.
98*9e94795aSAndroid Build Coastguard Worker      if ranges.extra.get('uses_shared_blocks'):
99*9e94795aSAndroid Build Coastguard Worker        file_ranges = ranges.extra['uses_shared_blocks']
100*9e94795aSAndroid Build Coastguard Worker      else:
101*9e94795aSAndroid Build Coastguard Worker        file_ranges = ranges
102*9e94795aSAndroid Build Coastguard Worker
103*9e94795aSAndroid Build Coastguard Worker      incomplete = file_ranges.extra.get('incomplete', False)
104*9e94795aSAndroid Build Coastguard Worker      if incomplete:
105*9e94795aSAndroid Build Coastguard Worker        logging.warning('Skipping %s that has incomplete block list', entry)
106*9e94795aSAndroid Build Coastguard Worker        continue
107*9e94795aSAndroid Build Coastguard Worker
108*9e94795aSAndroid Build Coastguard Worker      # If the file has non-monotonic ranges, read each range in order.
109*9e94795aSAndroid Build Coastguard Worker      if not file_ranges.monotonic:
110*9e94795aSAndroid Build Coastguard Worker        h = sha1()
111*9e94795aSAndroid Build Coastguard Worker        for file_range in file_ranges.extra['text_str'].split(' '):
112*9e94795aSAndroid Build Coastguard Worker          for data in image.ReadRangeSet(rangelib.RangeSet(file_range)):
113*9e94795aSAndroid Build Coastguard Worker            h.update(data)
114*9e94795aSAndroid Build Coastguard Worker        blocks_sha1 = h.hexdigest()
115*9e94795aSAndroid Build Coastguard Worker      else:
116*9e94795aSAndroid Build Coastguard Worker        blocks_sha1 = image.RangeSha1(file_ranges)
117*9e94795aSAndroid Build Coastguard Worker
118*9e94795aSAndroid Build Coastguard Worker      # The filename under unpacked directory, such as SYSTEM/bin/sh.
119*9e94795aSAndroid Build Coastguard Worker      unpacked_name = os.path.join(
120*9e94795aSAndroid Build Coastguard Worker          input_tmp, which.upper(), entry[(len(prefix) + 1):])
121*9e94795aSAndroid Build Coastguard Worker      unpacked_file = _ReadFile(entry, unpacked_name, True)
122*9e94795aSAndroid Build Coastguard Worker      file_sha1 = unpacked_file.sha1
123*9e94795aSAndroid Build Coastguard Worker      assert blocks_sha1 == file_sha1, \
124*9e94795aSAndroid Build Coastguard Worker          'file: %s, range: %s, blocks_sha1: %s, file_sha1: %s' % (
125*9e94795aSAndroid Build Coastguard Worker              entry, file_ranges, blocks_sha1, file_sha1)
126*9e94795aSAndroid Build Coastguard Worker
127*9e94795aSAndroid Build Coastguard Worker  logging.info('Validating file consistency.')
128*9e94795aSAndroid Build Coastguard Worker
129*9e94795aSAndroid Build Coastguard Worker  # TODO(b/79617342): Validate non-sparse images.
130*9e94795aSAndroid Build Coastguard Worker  if info_dict.get('extfs_sparse_flag') != '-s':
131*9e94795aSAndroid Build Coastguard Worker    logging.warning('Skipped due to target using non-sparse images')
132*9e94795aSAndroid Build Coastguard Worker    return
133*9e94795aSAndroid Build Coastguard Worker
134*9e94795aSAndroid Build Coastguard Worker  # Verify IMAGES/system.img if applicable.
135*9e94795aSAndroid Build Coastguard Worker  # Some targets are system.img-less.
136*9e94795aSAndroid Build Coastguard Worker  if 'IMAGES/system.img' in input_zip.namelist():
137*9e94795aSAndroid Build Coastguard Worker    CheckAllFiles('system')
138*9e94795aSAndroid Build Coastguard Worker
139*9e94795aSAndroid Build Coastguard Worker  # Verify IMAGES/vendor.img if applicable.
140*9e94795aSAndroid Build Coastguard Worker  if 'VENDOR/' in input_zip.namelist():
141*9e94795aSAndroid Build Coastguard Worker    CheckAllFiles('vendor')
142*9e94795aSAndroid Build Coastguard Worker
143*9e94795aSAndroid Build Coastguard Worker  # Not checking IMAGES/system_other.img since it doesn't have the map file.
144*9e94795aSAndroid Build Coastguard Worker
145*9e94795aSAndroid Build Coastguard Worker
146*9e94795aSAndroid Build Coastguard Workerdef ValidateInstallRecoveryScript(input_tmp, info_dict):
147*9e94795aSAndroid Build Coastguard Worker  """Validate the SHA-1 embedded in install-recovery.sh.
148*9e94795aSAndroid Build Coastguard Worker
149*9e94795aSAndroid Build Coastguard Worker  install-recovery.sh is written in common.py and has the following format:
150*9e94795aSAndroid Build Coastguard Worker
151*9e94795aSAndroid Build Coastguard Worker  1. full recovery:
152*9e94795aSAndroid Build Coastguard Worker  ...
153*9e94795aSAndroid Build Coastguard Worker  if ! applypatch --check type:device:size:sha1; then
154*9e94795aSAndroid Build Coastguard Worker    applypatch --flash /vendor/etc/recovery.img \\
155*9e94795aSAndroid Build Coastguard Worker        type:device:size:sha1 && \\
156*9e94795aSAndroid Build Coastguard Worker  ...
157*9e94795aSAndroid Build Coastguard Worker
158*9e94795aSAndroid Build Coastguard Worker  2. recovery from boot:
159*9e94795aSAndroid Build Coastguard Worker  ...
160*9e94795aSAndroid Build Coastguard Worker  if ! applypatch --check type:recovery_device:recovery_size:recovery_sha1; then
161*9e94795aSAndroid Build Coastguard Worker    applypatch [--bonus bonus_args] \\
162*9e94795aSAndroid Build Coastguard Worker        --patch /vendor/recovery-from-boot.p \\
163*9e94795aSAndroid Build Coastguard Worker        --source type:boot_device:boot_size:boot_sha1 \\
164*9e94795aSAndroid Build Coastguard Worker        --target type:recovery_device:recovery_size:recovery_sha1 && \\
165*9e94795aSAndroid Build Coastguard Worker  ...
166*9e94795aSAndroid Build Coastguard Worker
167*9e94795aSAndroid Build Coastguard Worker  For full recovery, we want to calculate the SHA-1 of /vendor/etc/recovery.img
168*9e94795aSAndroid Build Coastguard Worker  and compare it against the one embedded in the script. While for recovery
169*9e94795aSAndroid Build Coastguard Worker  from boot, we want to check the SHA-1 for both recovery.img and boot.img
170*9e94795aSAndroid Build Coastguard Worker  under IMAGES/.
171*9e94795aSAndroid Build Coastguard Worker  """
172*9e94795aSAndroid Build Coastguard Worker
173*9e94795aSAndroid Build Coastguard Worker  board_uses_vendorimage = info_dict.get("board_uses_vendorimage") == "true"
174*9e94795aSAndroid Build Coastguard Worker
175*9e94795aSAndroid Build Coastguard Worker  if board_uses_vendorimage:
176*9e94795aSAndroid Build Coastguard Worker    script_path = 'VENDOR/bin/install-recovery.sh'
177*9e94795aSAndroid Build Coastguard Worker    recovery_img = 'VENDOR/etc/recovery.img'
178*9e94795aSAndroid Build Coastguard Worker  else:
179*9e94795aSAndroid Build Coastguard Worker    script_path = 'SYSTEM/vendor/bin/install-recovery.sh'
180*9e94795aSAndroid Build Coastguard Worker    recovery_img = 'SYSTEM/vendor/etc/recovery.img'
181*9e94795aSAndroid Build Coastguard Worker
182*9e94795aSAndroid Build Coastguard Worker  if not os.path.exists(os.path.join(input_tmp, script_path)):
183*9e94795aSAndroid Build Coastguard Worker    logging.info('%s does not exist in input_tmp', script_path)
184*9e94795aSAndroid Build Coastguard Worker    return
185*9e94795aSAndroid Build Coastguard Worker
186*9e94795aSAndroid Build Coastguard Worker  logging.info('Checking %s', script_path)
187*9e94795aSAndroid Build Coastguard Worker  with open(os.path.join(input_tmp, script_path), 'r') as script:
188*9e94795aSAndroid Build Coastguard Worker    lines = script.read().strip().split('\n')
189*9e94795aSAndroid Build Coastguard Worker  assert len(lines) >= 10
190*9e94795aSAndroid Build Coastguard Worker  check_cmd = re.search(r'if ! applypatch --check (\w+:.+:\w+:\w+);',
191*9e94795aSAndroid Build Coastguard Worker                        lines[1].strip())
192*9e94795aSAndroid Build Coastguard Worker  check_partition = check_cmd.group(1)
193*9e94795aSAndroid Build Coastguard Worker  assert len(check_partition.split(':')) == 4
194*9e94795aSAndroid Build Coastguard Worker
195*9e94795aSAndroid Build Coastguard Worker  full_recovery_image = info_dict.get("full_recovery_image") == "true"
196*9e94795aSAndroid Build Coastguard Worker  if full_recovery_image:
197*9e94795aSAndroid Build Coastguard Worker    assert len(lines) == 10, "Invalid line count: {}".format(lines)
198*9e94795aSAndroid Build Coastguard Worker
199*9e94795aSAndroid Build Coastguard Worker    # Expect something like "EMMC:/dev/block/recovery:28:5f9c..62e3".
200*9e94795aSAndroid Build Coastguard Worker    target = re.search(r'--target (.+) &&', lines[4].strip())
201*9e94795aSAndroid Build Coastguard Worker    assert target is not None, \
202*9e94795aSAndroid Build Coastguard Worker        "Failed to parse target line \"{}\"".format(lines[4])
203*9e94795aSAndroid Build Coastguard Worker    flash_partition = target.group(1)
204*9e94795aSAndroid Build Coastguard Worker
205*9e94795aSAndroid Build Coastguard Worker    # Check we have the same recovery target in the check and flash commands.
206*9e94795aSAndroid Build Coastguard Worker    assert check_partition == flash_partition, \
207*9e94795aSAndroid Build Coastguard Worker        "Mismatching targets: {} vs {}".format(
208*9e94795aSAndroid Build Coastguard Worker            check_partition, flash_partition)
209*9e94795aSAndroid Build Coastguard Worker
210*9e94795aSAndroid Build Coastguard Worker    # Validate the SHA-1 of the recovery image.
211*9e94795aSAndroid Build Coastguard Worker    recovery_sha1 = flash_partition.split(':')[3]
212*9e94795aSAndroid Build Coastguard Worker    ValidateFileAgainstSha1(
213*9e94795aSAndroid Build Coastguard Worker        input_tmp, 'recovery.img', recovery_img, recovery_sha1)
214*9e94795aSAndroid Build Coastguard Worker  else:
215*9e94795aSAndroid Build Coastguard Worker    assert len(lines) == 11, "Invalid line count: {}".format(lines)
216*9e94795aSAndroid Build Coastguard Worker
217*9e94795aSAndroid Build Coastguard Worker    # --source boot_type:boot_device:boot_size:boot_sha1
218*9e94795aSAndroid Build Coastguard Worker    source = re.search(r'--source (\w+:.+:\w+:\w+) \\', lines[4].strip())
219*9e94795aSAndroid Build Coastguard Worker    assert source is not None, \
220*9e94795aSAndroid Build Coastguard Worker        "Failed to parse source line \"{}\"".format(lines[4])
221*9e94795aSAndroid Build Coastguard Worker
222*9e94795aSAndroid Build Coastguard Worker    source_partition = source.group(1)
223*9e94795aSAndroid Build Coastguard Worker    source_info = source_partition.split(':')
224*9e94795aSAndroid Build Coastguard Worker    assert len(source_info) == 4, \
225*9e94795aSAndroid Build Coastguard Worker        "Invalid source partition: {}".format(source_partition)
226*9e94795aSAndroid Build Coastguard Worker    ValidateFileAgainstSha1(input_tmp, file_name='boot.img',
227*9e94795aSAndroid Build Coastguard Worker                            file_path='IMAGES/boot.img',
228*9e94795aSAndroid Build Coastguard Worker                            expected_sha1=source_info[3])
229*9e94795aSAndroid Build Coastguard Worker
230*9e94795aSAndroid Build Coastguard Worker    # --target recovery_type:recovery_device:recovery_size:recovery_sha1
231*9e94795aSAndroid Build Coastguard Worker    target = re.search(r'--target (\w+:.+:\w+:\w+) && \\', lines[5].strip())
232*9e94795aSAndroid Build Coastguard Worker    assert target is not None, \
233*9e94795aSAndroid Build Coastguard Worker        "Failed to parse target line \"{}\"".format(lines[5])
234*9e94795aSAndroid Build Coastguard Worker    target_partition = target.group(1)
235*9e94795aSAndroid Build Coastguard Worker
236*9e94795aSAndroid Build Coastguard Worker    # Check we have the same recovery target in the check and patch commands.
237*9e94795aSAndroid Build Coastguard Worker    assert check_partition == target_partition, \
238*9e94795aSAndroid Build Coastguard Worker        "Mismatching targets: {} vs {}".format(
239*9e94795aSAndroid Build Coastguard Worker            check_partition, target_partition)
240*9e94795aSAndroid Build Coastguard Worker
241*9e94795aSAndroid Build Coastguard Worker    recovery_info = target_partition.split(':')
242*9e94795aSAndroid Build Coastguard Worker    assert len(recovery_info) == 4, \
243*9e94795aSAndroid Build Coastguard Worker        "Invalid target partition: {}".format(target_partition)
244*9e94795aSAndroid Build Coastguard Worker    ValidateFileAgainstSha1(input_tmp, file_name='recovery.img',
245*9e94795aSAndroid Build Coastguard Worker                            file_path='IMAGES/recovery.img',
246*9e94795aSAndroid Build Coastguard Worker                            expected_sha1=recovery_info[3])
247*9e94795aSAndroid Build Coastguard Worker
248*9e94795aSAndroid Build Coastguard Worker  logging.info('Done checking %s', script_path)
249*9e94795aSAndroid Build Coastguard Worker
250*9e94795aSAndroid Build Coastguard Worker
251*9e94795aSAndroid Build Coastguard Worker# Symlink files in `src` to `dst`, if the files do not
252*9e94795aSAndroid Build Coastguard Worker# already exists in `dst` directory.
253*9e94795aSAndroid Build Coastguard Workerdef symlinkIfNotExists(src, dst):
254*9e94795aSAndroid Build Coastguard Worker  if not os.path.isdir(src):
255*9e94795aSAndroid Build Coastguard Worker    return
256*9e94795aSAndroid Build Coastguard Worker  for filename in os.listdir(src):
257*9e94795aSAndroid Build Coastguard Worker    if os.path.exists(os.path.join(dst, filename)):
258*9e94795aSAndroid Build Coastguard Worker      continue
259*9e94795aSAndroid Build Coastguard Worker    os.symlink(os.path.join(src, filename), os.path.join(dst, filename))
260*9e94795aSAndroid Build Coastguard Worker
261*9e94795aSAndroid Build Coastguard Worker
262*9e94795aSAndroid Build Coastguard Workerdef ValidatePartitionFingerprints(input_tmp, info_dict):
263*9e94795aSAndroid Build Coastguard Worker  build_info = common.BuildInfo(info_dict)
264*9e94795aSAndroid Build Coastguard Worker  # Expected format:
265*9e94795aSAndroid Build Coastguard Worker  #  Prop: com.android.build.vendor.fingerprint -> 'generic/aosp_cf_x86_64_phone/vsoc_x86_64:S/AOSP.MASTER/7335886:userdebug/test-keys'
266*9e94795aSAndroid Build Coastguard Worker  #  Prop: com.android.build.vendor_boot.fingerprint -> 'generic/aosp_cf_x86_64_phone/vsoc_x86_64:S/AOSP.MASTER/7335886:userdebug/test-keys'
267*9e94795aSAndroid Build Coastguard Worker  p = re.compile(
268*9e94795aSAndroid Build Coastguard Worker      r"Prop: com.android.build.(?P<partition>\w+).fingerprint -> '(?P<fingerprint>[\w\/:\.-]+)'")
269*9e94795aSAndroid Build Coastguard Worker  for vbmeta_partition in ["vbmeta", "vbmeta_system"]:
270*9e94795aSAndroid Build Coastguard Worker    image = os.path.join(input_tmp, "IMAGES", vbmeta_partition + ".img")
271*9e94795aSAndroid Build Coastguard Worker    if not os.path.exists(image):
272*9e94795aSAndroid Build Coastguard Worker      assert vbmeta_partition != "vbmeta",\
273*9e94795aSAndroid Build Coastguard Worker          "{} is a required partition for AVB.".format(
274*9e94795aSAndroid Build Coastguard Worker              vbmeta_partition)
275*9e94795aSAndroid Build Coastguard Worker      logging.info("vb partition %s not present, skipping", vbmeta_partition)
276*9e94795aSAndroid Build Coastguard Worker      continue
277*9e94795aSAndroid Build Coastguard Worker
278*9e94795aSAndroid Build Coastguard Worker    output = common.RunAndCheckOutput(
279*9e94795aSAndroid Build Coastguard Worker        [info_dict["avb_avbtool"], "info_image", "--image", image])
280*9e94795aSAndroid Build Coastguard Worker    matches = p.findall(output)
281*9e94795aSAndroid Build Coastguard Worker    for (partition, fingerprint) in matches:
282*9e94795aSAndroid Build Coastguard Worker      actual_fingerprint = build_info.GetPartitionFingerprint(
283*9e94795aSAndroid Build Coastguard Worker          partition)
284*9e94795aSAndroid Build Coastguard Worker      if actual_fingerprint is None:
285*9e94795aSAndroid Build Coastguard Worker        logging.warning(
286*9e94795aSAndroid Build Coastguard Worker            "Failed to get fingerprint for partition %s", partition)
287*9e94795aSAndroid Build Coastguard Worker        continue
288*9e94795aSAndroid Build Coastguard Worker      assert fingerprint == actual_fingerprint, "Fingerprint mismatch for partition {}, expected: {} actual: {}".format(
289*9e94795aSAndroid Build Coastguard Worker          partition, fingerprint, actual_fingerprint)
290*9e94795aSAndroid Build Coastguard Worker
291*9e94795aSAndroid Build Coastguard Worker
292*9e94795aSAndroid Build Coastguard Workerdef ValidateVerifiedBootImages(input_tmp, info_dict, options):
293*9e94795aSAndroid Build Coastguard Worker  """Validates the Verified Boot related images.
294*9e94795aSAndroid Build Coastguard Worker
295*9e94795aSAndroid Build Coastguard Worker  For Verified Boot 1.0, it verifies the signatures of the bootable images
296*9e94795aSAndroid Build Coastguard Worker  (boot/recovery etc), as well as the dm-verity metadata in system images
297*9e94795aSAndroid Build Coastguard Worker  (system/vendor/product). For Verified Boot 2.0, it calls avbtool to verify
298*9e94795aSAndroid Build Coastguard Worker  vbmeta.img, which in turn verifies all the descriptors listed in vbmeta.
299*9e94795aSAndroid Build Coastguard Worker
300*9e94795aSAndroid Build Coastguard Worker  Args:
301*9e94795aSAndroid Build Coastguard Worker    input_tmp: The top-level directory of unpacked target-files.zip.
302*9e94795aSAndroid Build Coastguard Worker    info_dict: The loaded info dict.
303*9e94795aSAndroid Build Coastguard Worker    options: A dict that contains the user-supplied public keys to be used for
304*9e94795aSAndroid Build Coastguard Worker        image verification. In particular, 'verity_key' is used to verify the
305*9e94795aSAndroid Build Coastguard Worker        bootable images in VB 1.0, and the vbmeta image in VB 2.0, where
306*9e94795aSAndroid Build Coastguard Worker        applicable. 'verity_key_mincrypt' will be used to verify the system
307*9e94795aSAndroid Build Coastguard Worker        images in VB 1.0.
308*9e94795aSAndroid Build Coastguard Worker
309*9e94795aSAndroid Build Coastguard Worker  Raises:
310*9e94795aSAndroid Build Coastguard Worker    AssertionError: On any verification failure.
311*9e94795aSAndroid Build Coastguard Worker  """
312*9e94795aSAndroid Build Coastguard Worker  # See bug 159299583
313*9e94795aSAndroid Build Coastguard Worker  # After commit 5277d1015, some images (e.g. acpio.img and tos.img) are no
314*9e94795aSAndroid Build Coastguard Worker  # longer copied from RADIO to the IMAGES folder. But avbtool assumes that
315*9e94795aSAndroid Build Coastguard Worker  # images are in IMAGES folder. So we symlink them.
316*9e94795aSAndroid Build Coastguard Worker  symlinkIfNotExists(os.path.join(input_tmp, "RADIO"),
317*9e94795aSAndroid Build Coastguard Worker                     os.path.join(input_tmp, "IMAGES"))
318*9e94795aSAndroid Build Coastguard Worker  # Verified boot 1.0 (images signed with boot_signer and verity_signer).
319*9e94795aSAndroid Build Coastguard Worker  if info_dict.get('boot_signer') == 'true':
320*9e94795aSAndroid Build Coastguard Worker    logging.info('Verifying Verified Boot images...')
321*9e94795aSAndroid Build Coastguard Worker
322*9e94795aSAndroid Build Coastguard Worker    # Verify the boot/recovery images (signed with boot_signer), against the
323*9e94795aSAndroid Build Coastguard Worker    # given X.509 encoded pubkey (or falling back to the one in the info_dict if
324*9e94795aSAndroid Build Coastguard Worker    # none given).
325*9e94795aSAndroid Build Coastguard Worker    verity_key = options['verity_key']
326*9e94795aSAndroid Build Coastguard Worker    if verity_key is None:
327*9e94795aSAndroid Build Coastguard Worker      verity_key = info_dict['verity_key'] + '.x509.pem'
328*9e94795aSAndroid Build Coastguard Worker    for image in ('boot.img', 'recovery.img', 'recovery-two-step.img'):
329*9e94795aSAndroid Build Coastguard Worker      if image == 'recovery-two-step.img':
330*9e94795aSAndroid Build Coastguard Worker        image_path = os.path.join(input_tmp, 'OTA', image)
331*9e94795aSAndroid Build Coastguard Worker      else:
332*9e94795aSAndroid Build Coastguard Worker        image_path = os.path.join(input_tmp, 'IMAGES', image)
333*9e94795aSAndroid Build Coastguard Worker      if not os.path.exists(image_path):
334*9e94795aSAndroid Build Coastguard Worker        continue
335*9e94795aSAndroid Build Coastguard Worker
336*9e94795aSAndroid Build Coastguard Worker      cmd = ['boot_signer', '-verify', image_path, '-certificate', verity_key]
337*9e94795aSAndroid Build Coastguard Worker      proc = common.Run(cmd)
338*9e94795aSAndroid Build Coastguard Worker      stdoutdata, _ = proc.communicate()
339*9e94795aSAndroid Build Coastguard Worker      assert proc.returncode == 0, \
340*9e94795aSAndroid Build Coastguard Worker          'Failed to verify {} with boot_signer:\n{}'.format(image, stdoutdata)
341*9e94795aSAndroid Build Coastguard Worker      logging.info(
342*9e94795aSAndroid Build Coastguard Worker          'Verified %s with boot_signer (key: %s):\n%s', image, verity_key,
343*9e94795aSAndroid Build Coastguard Worker          stdoutdata.rstrip())
344*9e94795aSAndroid Build Coastguard Worker
345*9e94795aSAndroid Build Coastguard Worker  # Verify verity signed system images in Verified Boot 1.0. Note that not using
346*9e94795aSAndroid Build Coastguard Worker  # 'elif' here, since 'boot_signer' and 'verity' are not bundled in VB 1.0.
347*9e94795aSAndroid Build Coastguard Worker  if info_dict.get('verity') == 'true':
348*9e94795aSAndroid Build Coastguard Worker    # First verify that the verity key is built into the root image (regardless
349*9e94795aSAndroid Build Coastguard Worker    # of system-as-root).
350*9e94795aSAndroid Build Coastguard Worker    verity_key_mincrypt = os.path.join(input_tmp, 'ROOT', 'verity_key')
351*9e94795aSAndroid Build Coastguard Worker    assert os.path.exists(verity_key_mincrypt), 'Missing verity_key'
352*9e94795aSAndroid Build Coastguard Worker
353*9e94795aSAndroid Build Coastguard Worker    # Verify /verity_key matches the one given via command line, if any.
354*9e94795aSAndroid Build Coastguard Worker    if options['verity_key_mincrypt'] is None:
355*9e94795aSAndroid Build Coastguard Worker      logging.warn(
356*9e94795aSAndroid Build Coastguard Worker          'Skipped checking the content of /verity_key, as the key file not '
357*9e94795aSAndroid Build Coastguard Worker          'provided. Use --verity_key_mincrypt to specify.')
358*9e94795aSAndroid Build Coastguard Worker    else:
359*9e94795aSAndroid Build Coastguard Worker      expected_key = options['verity_key_mincrypt']
360*9e94795aSAndroid Build Coastguard Worker      assert filecmp.cmp(expected_key, verity_key_mincrypt, shallow=False), \
361*9e94795aSAndroid Build Coastguard Worker          "Mismatching mincrypt verity key files"
362*9e94795aSAndroid Build Coastguard Worker      logging.info('Verified the content of /verity_key')
363*9e94795aSAndroid Build Coastguard Worker
364*9e94795aSAndroid Build Coastguard Worker    verity_key_ramdisk = os.path.join(
365*9e94795aSAndroid Build Coastguard Worker        input_tmp, 'BOOT', 'RAMDISK', 'verity_key')
366*9e94795aSAndroid Build Coastguard Worker    assert os.path.exists(
367*9e94795aSAndroid Build Coastguard Worker        verity_key_ramdisk), 'Missing verity_key in ramdisk'
368*9e94795aSAndroid Build Coastguard Worker
369*9e94795aSAndroid Build Coastguard Worker    assert filecmp.cmp(
370*9e94795aSAndroid Build Coastguard Worker        verity_key_mincrypt, verity_key_ramdisk, shallow=False), \
371*9e94795aSAndroid Build Coastguard Worker        'Mismatching verity_key files in root and ramdisk'
372*9e94795aSAndroid Build Coastguard Worker    logging.info('Verified the content of /verity_key in ramdisk')
373*9e94795aSAndroid Build Coastguard Worker
374*9e94795aSAndroid Build Coastguard Worker    # Then verify the verity signed system/vendor/product images, against the
375*9e94795aSAndroid Build Coastguard Worker    # verity pubkey in mincrypt format.
376*9e94795aSAndroid Build Coastguard Worker    for image in ('system.img', 'vendor.img', 'product.img'):
377*9e94795aSAndroid Build Coastguard Worker      image_path = os.path.join(input_tmp, 'IMAGES', image)
378*9e94795aSAndroid Build Coastguard Worker
379*9e94795aSAndroid Build Coastguard Worker      # We are not checking if the image is actually enabled via info_dict (e.g.
380*9e94795aSAndroid Build Coastguard Worker      # 'system_verity_block_device=...'). Because it's most likely a bug that
381*9e94795aSAndroid Build Coastguard Worker      # skips signing some of the images in signed target-files.zip, while
382*9e94795aSAndroid Build Coastguard Worker      # having the top-level verity flag enabled.
383*9e94795aSAndroid Build Coastguard Worker      if not os.path.exists(image_path):
384*9e94795aSAndroid Build Coastguard Worker        continue
385*9e94795aSAndroid Build Coastguard Worker
386*9e94795aSAndroid Build Coastguard Worker      cmd = ['verity_verifier', image_path, '-mincrypt', verity_key_mincrypt]
387*9e94795aSAndroid Build Coastguard Worker      proc = common.Run(cmd)
388*9e94795aSAndroid Build Coastguard Worker      stdoutdata, _ = proc.communicate()
389*9e94795aSAndroid Build Coastguard Worker      assert proc.returncode == 0, \
390*9e94795aSAndroid Build Coastguard Worker          'Failed to verify {} with verity_verifier (key: {}):\n{}'.format(
391*9e94795aSAndroid Build Coastguard Worker              image, verity_key_mincrypt, stdoutdata)
392*9e94795aSAndroid Build Coastguard Worker      logging.info(
393*9e94795aSAndroid Build Coastguard Worker          'Verified %s with verity_verifier (key: %s):\n%s', image,
394*9e94795aSAndroid Build Coastguard Worker          verity_key_mincrypt, stdoutdata.rstrip())
395*9e94795aSAndroid Build Coastguard Worker
396*9e94795aSAndroid Build Coastguard Worker  # Handle the case of Verified Boot 2.0 (AVB).
397*9e94795aSAndroid Build Coastguard Worker  if info_dict.get("avb_building_vbmeta_image") == "true":
398*9e94795aSAndroid Build Coastguard Worker    logging.info('Verifying Verified Boot 2.0 (AVB) images...')
399*9e94795aSAndroid Build Coastguard Worker
400*9e94795aSAndroid Build Coastguard Worker    key = options['verity_key']
401*9e94795aSAndroid Build Coastguard Worker    if key is None:
402*9e94795aSAndroid Build Coastguard Worker      key = info_dict['avb_vbmeta_key_path']
403*9e94795aSAndroid Build Coastguard Worker
404*9e94795aSAndroid Build Coastguard Worker    ValidatePartitionFingerprints(input_tmp, info_dict)
405*9e94795aSAndroid Build Coastguard Worker
406*9e94795aSAndroid Build Coastguard Worker    # avbtool verifies all the images that have descriptors listed in vbmeta.
407*9e94795aSAndroid Build Coastguard Worker    # Using `--follow_chain_partitions` so it would additionally verify chained
408*9e94795aSAndroid Build Coastguard Worker    # vbmeta partitions (e.g. vbmeta_system).
409*9e94795aSAndroid Build Coastguard Worker    image = os.path.join(input_tmp, 'IMAGES', 'vbmeta.img')
410*9e94795aSAndroid Build Coastguard Worker    cmd = [info_dict['avb_avbtool'], 'verify_image', '--image', image,
411*9e94795aSAndroid Build Coastguard Worker           '--follow_chain_partitions']
412*9e94795aSAndroid Build Coastguard Worker
413*9e94795aSAndroid Build Coastguard Worker    # Custom images.
414*9e94795aSAndroid Build Coastguard Worker    custom_partitions = info_dict.get(
415*9e94795aSAndroid Build Coastguard Worker        "avb_custom_images_partition_list", "").strip().split()
416*9e94795aSAndroid Build Coastguard Worker
417*9e94795aSAndroid Build Coastguard Worker    # Append the args for chained partitions if any.
418*9e94795aSAndroid Build Coastguard Worker    for partition in (common.AVB_PARTITIONS + common.AVB_VBMETA_PARTITIONS +
419*9e94795aSAndroid Build Coastguard Worker                      tuple(custom_partitions)):
420*9e94795aSAndroid Build Coastguard Worker      key_name = 'avb_' + partition + '_key_path'
421*9e94795aSAndroid Build Coastguard Worker      if info_dict.get(key_name) is not None:
422*9e94795aSAndroid Build Coastguard Worker        if info_dict.get('ab_update') != 'true' and partition == 'recovery':
423*9e94795aSAndroid Build Coastguard Worker          continue
424*9e94795aSAndroid Build Coastguard Worker
425*9e94795aSAndroid Build Coastguard Worker        # Use the key file from command line if specified; otherwise fall back
426*9e94795aSAndroid Build Coastguard Worker        # to the one in info dict.
427*9e94795aSAndroid Build Coastguard Worker        key_file = options.get(key_name, info_dict[key_name])
428*9e94795aSAndroid Build Coastguard Worker        chained_partition_arg = common.GetAvbChainedPartitionArg(
429*9e94795aSAndroid Build Coastguard Worker            partition, info_dict, key_file)
430*9e94795aSAndroid Build Coastguard Worker        cmd.extend(['--expected_chain_partition',
431*9e94795aSAndroid Build Coastguard Worker                    chained_partition_arg.to_string()])
432*9e94795aSAndroid Build Coastguard Worker
433*9e94795aSAndroid Build Coastguard Worker    # Handle the boot image with a non-default name, e.g. boot-5.4.img
434*9e94795aSAndroid Build Coastguard Worker    boot_images = info_dict.get("boot_images")
435*9e94795aSAndroid Build Coastguard Worker    if boot_images:
436*9e94795aSAndroid Build Coastguard Worker      # we used the 1st boot image to generate the vbmeta. Rename the filename
437*9e94795aSAndroid Build Coastguard Worker      # to boot.img so that avbtool can find it correctly.
438*9e94795aSAndroid Build Coastguard Worker      first_image_name = boot_images.split()[0]
439*9e94795aSAndroid Build Coastguard Worker      first_image_path = os.path.join(input_tmp, 'IMAGES', first_image_name)
440*9e94795aSAndroid Build Coastguard Worker      assert os.path.isfile(first_image_path)
441*9e94795aSAndroid Build Coastguard Worker      renamed_boot_image_path = os.path.join(input_tmp, 'IMAGES', 'boot.img')
442*9e94795aSAndroid Build Coastguard Worker      os.rename(first_image_path, renamed_boot_image_path)
443*9e94795aSAndroid Build Coastguard Worker
444*9e94795aSAndroid Build Coastguard Worker    proc = common.Run(cmd)
445*9e94795aSAndroid Build Coastguard Worker    stdoutdata, _ = proc.communicate()
446*9e94795aSAndroid Build Coastguard Worker    assert proc.returncode == 0, \
447*9e94795aSAndroid Build Coastguard Worker        'Failed to verify {} with avbtool (key: {}):\n{}'.format(
448*9e94795aSAndroid Build Coastguard Worker            image, key, stdoutdata)
449*9e94795aSAndroid Build Coastguard Worker
450*9e94795aSAndroid Build Coastguard Worker    logging.info(
451*9e94795aSAndroid Build Coastguard Worker        'Verified %s with avbtool (key: %s):\n%s', image, key,
452*9e94795aSAndroid Build Coastguard Worker        stdoutdata.rstrip())
453*9e94795aSAndroid Build Coastguard Worker
454*9e94795aSAndroid Build Coastguard Worker    # avbtool verifies recovery image for non-A/B devices.
455*9e94795aSAndroid Build Coastguard Worker    if (info_dict.get('ab_update') != 'true' and
456*9e94795aSAndroid Build Coastguard Worker            info_dict.get('no_recovery') != 'true'):
457*9e94795aSAndroid Build Coastguard Worker      image = os.path.join(input_tmp, 'IMAGES', 'recovery.img')
458*9e94795aSAndroid Build Coastguard Worker      key = info_dict['avb_recovery_key_path']
459*9e94795aSAndroid Build Coastguard Worker      cmd = [info_dict['avb_avbtool'], 'verify_image', '--image', image,
460*9e94795aSAndroid Build Coastguard Worker             '--key', key]
461*9e94795aSAndroid Build Coastguard Worker      proc = common.Run(cmd)
462*9e94795aSAndroid Build Coastguard Worker      stdoutdata, _ = proc.communicate()
463*9e94795aSAndroid Build Coastguard Worker      assert proc.returncode == 0, \
464*9e94795aSAndroid Build Coastguard Worker          'Failed to verify {} with avbtool (key: {}):\n{}'.format(
465*9e94795aSAndroid Build Coastguard Worker              image, key, stdoutdata)
466*9e94795aSAndroid Build Coastguard Worker      logging.info(
467*9e94795aSAndroid Build Coastguard Worker          'Verified %s with avbtool (key: %s):\n%s', image, key,
468*9e94795aSAndroid Build Coastguard Worker          stdoutdata.rstrip())
469*9e94795aSAndroid Build Coastguard Worker
470*9e94795aSAndroid Build Coastguard Worker
471*9e94795aSAndroid Build Coastguard Workerdef CheckDataInconsistency(lines):
472*9e94795aSAndroid Build Coastguard Worker  build_prop = {}
473*9e94795aSAndroid Build Coastguard Worker  for line in lines:
474*9e94795aSAndroid Build Coastguard Worker    if line.startswith("import") or line.startswith("#"):
475*9e94795aSAndroid Build Coastguard Worker      continue
476*9e94795aSAndroid Build Coastguard Worker    if "=" not in line:
477*9e94795aSAndroid Build Coastguard Worker      continue
478*9e94795aSAndroid Build Coastguard Worker
479*9e94795aSAndroid Build Coastguard Worker    key, value = line.rstrip().split("=", 1)
480*9e94795aSAndroid Build Coastguard Worker    if key in build_prop:
481*9e94795aSAndroid Build Coastguard Worker      logging.info("Duplicated key found for {}".format(key))
482*9e94795aSAndroid Build Coastguard Worker      if value != build_prop[key]:
483*9e94795aSAndroid Build Coastguard Worker        logging.error("Key {} is defined twice with different values {} vs {}"
484*9e94795aSAndroid Build Coastguard Worker                      .format(key, value, build_prop[key]))
485*9e94795aSAndroid Build Coastguard Worker        return key
486*9e94795aSAndroid Build Coastguard Worker    build_prop[key] = value
487*9e94795aSAndroid Build Coastguard Worker
488*9e94795aSAndroid Build Coastguard Worker
489*9e94795aSAndroid Build Coastguard Workerdef CheckBuildPropDuplicity(input_tmp):
490*9e94795aSAndroid Build Coastguard Worker  """Check all buld.prop files inside directory input_tmp, raise error
491*9e94795aSAndroid Build Coastguard Worker  if they contain duplicates"""
492*9e94795aSAndroid Build Coastguard Worker
493*9e94795aSAndroid Build Coastguard Worker  if not os.path.isdir(input_tmp):
494*9e94795aSAndroid Build Coastguard Worker    raise ValueError("Expect {} to be a directory".format(input_tmp))
495*9e94795aSAndroid Build Coastguard Worker  for name in os.listdir(input_tmp):
496*9e94795aSAndroid Build Coastguard Worker    if not name.isupper():
497*9e94795aSAndroid Build Coastguard Worker      continue
498*9e94795aSAndroid Build Coastguard Worker    for prop_file in ['build.prop', 'etc/build.prop']:
499*9e94795aSAndroid Build Coastguard Worker      path = os.path.join(input_tmp, name, prop_file)
500*9e94795aSAndroid Build Coastguard Worker      if not os.path.exists(path):
501*9e94795aSAndroid Build Coastguard Worker        continue
502*9e94795aSAndroid Build Coastguard Worker      logging.info("Checking {}".format(path))
503*9e94795aSAndroid Build Coastguard Worker      with open(path, 'r') as fp:
504*9e94795aSAndroid Build Coastguard Worker        dupKey = CheckDataInconsistency(fp.readlines())
505*9e94795aSAndroid Build Coastguard Worker        if dupKey:
506*9e94795aSAndroid Build Coastguard Worker          raise ValueError("{} contains duplicate keys for {}".format(
507*9e94795aSAndroid Build Coastguard Worker              path, dupKey))
508*9e94795aSAndroid Build Coastguard Worker
509*9e94795aSAndroid Build Coastguard Worker
510*9e94795aSAndroid Build Coastguard Workerdef main():
511*9e94795aSAndroid Build Coastguard Worker  parser = argparse.ArgumentParser(
512*9e94795aSAndroid Build Coastguard Worker      description=__doc__,
513*9e94795aSAndroid Build Coastguard Worker      formatter_class=argparse.RawDescriptionHelpFormatter)
514*9e94795aSAndroid Build Coastguard Worker  parser.add_argument(
515*9e94795aSAndroid Build Coastguard Worker      'target_files',
516*9e94795aSAndroid Build Coastguard Worker      help='the input target_files.zip to be validated')
517*9e94795aSAndroid Build Coastguard Worker  parser.add_argument(
518*9e94795aSAndroid Build Coastguard Worker      '--verity_key',
519*9e94795aSAndroid Build Coastguard Worker      help='the verity public key to verify the bootable images (Verified '
520*9e94795aSAndroid Build Coastguard Worker           'Boot 1.0), or the vbmeta image (Verified Boot 2.0, aka AVB), where '
521*9e94795aSAndroid Build Coastguard Worker           'applicable')
522*9e94795aSAndroid Build Coastguard Worker  for partition in common.AVB_PARTITIONS + common.AVB_VBMETA_PARTITIONS:
523*9e94795aSAndroid Build Coastguard Worker    parser.add_argument(
524*9e94795aSAndroid Build Coastguard Worker        '--avb_' + partition + '_key_path',
525*9e94795aSAndroid Build Coastguard Worker        help='the public or private key in PEM format to verify AVB chained '
526*9e94795aSAndroid Build Coastguard Worker             'partition of {}'.format(partition))
527*9e94795aSAndroid Build Coastguard Worker  parser.add_argument(
528*9e94795aSAndroid Build Coastguard Worker      '--verity_key_mincrypt',
529*9e94795aSAndroid Build Coastguard Worker      help='the verity public key in mincrypt format to verify the system '
530*9e94795aSAndroid Build Coastguard Worker           'images, if target using Verified Boot 1.0')
531*9e94795aSAndroid Build Coastguard Worker  args = parser.parse_args()
532*9e94795aSAndroid Build Coastguard Worker
533*9e94795aSAndroid Build Coastguard Worker  # Unprovided args will have 'None' as the value.
534*9e94795aSAndroid Build Coastguard Worker  options = vars(args)
535*9e94795aSAndroid Build Coastguard Worker
536*9e94795aSAndroid Build Coastguard Worker  logging_format = '%(asctime)s - %(filename)s - %(levelname)-8s: %(message)s'
537*9e94795aSAndroid Build Coastguard Worker  date_format = '%Y/%m/%d %H:%M:%S'
538*9e94795aSAndroid Build Coastguard Worker  logging.basicConfig(level=logging.INFO, format=logging_format,
539*9e94795aSAndroid Build Coastguard Worker                      datefmt=date_format)
540*9e94795aSAndroid Build Coastguard Worker
541*9e94795aSAndroid Build Coastguard Worker  logging.info("Unzipping the input target_files.zip: %s", args.target_files)
542*9e94795aSAndroid Build Coastguard Worker  input_tmp = common.UnzipTemp(args.target_files)
543*9e94795aSAndroid Build Coastguard Worker
544*9e94795aSAndroid Build Coastguard Worker  info_dict = common.LoadInfoDict(input_tmp)
545*9e94795aSAndroid Build Coastguard Worker  with zipfile.ZipFile(args.target_files, 'r', allowZip64=True) as input_zip:
546*9e94795aSAndroid Build Coastguard Worker    ValidateFileConsistency(input_zip, input_tmp, info_dict)
547*9e94795aSAndroid Build Coastguard Worker
548*9e94795aSAndroid Build Coastguard Worker  CheckBuildPropDuplicity(input_tmp)
549*9e94795aSAndroid Build Coastguard Worker
550*9e94795aSAndroid Build Coastguard Worker  ValidateInstallRecoveryScript(input_tmp, info_dict)
551*9e94795aSAndroid Build Coastguard Worker
552*9e94795aSAndroid Build Coastguard Worker  ValidateVerifiedBootImages(input_tmp, info_dict, options)
553*9e94795aSAndroid Build Coastguard Worker
554*9e94795aSAndroid Build Coastguard Worker  # TODO: Check if the OTA keys have been properly updated (the ones on /system,
555*9e94795aSAndroid Build Coastguard Worker  # in recovery image).
556*9e94795aSAndroid Build Coastguard Worker
557*9e94795aSAndroid Build Coastguard Worker  logging.info("Done.")
558*9e94795aSAndroid Build Coastguard Worker
559*9e94795aSAndroid Build Coastguard Worker
560*9e94795aSAndroid Build Coastguard Workerif __name__ == '__main__':
561*9e94795aSAndroid Build Coastguard Worker  try:
562*9e94795aSAndroid Build Coastguard Worker    main()
563*9e94795aSAndroid Build Coastguard Worker  finally:
564*9e94795aSAndroid Build Coastguard Worker    common.Cleanup()
565