blob: 8c0073382f4d256e8970a5466059cea96788816e [file] [log] [blame]
Doug Zongkereef39442009-04-02 12:14:19 -07001#!/usr/bin/env python
2#
3# Copyright (C) 2008 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"""
18Signs all the APK files in a target-files zipfile, producing a new
19target-files zip.
20
21Usage: sign_target_files_apks [flags] input_target_files output_target_files
22
Doug Zongkereef39442009-04-02 12:14:19 -070023 -e (--extra_apks) <name,name,...=key>
Tao Baoaa7e9932019-03-15 09:37:01 -070024 Add extra APK/APEX name/key pairs as though they appeared in apkcerts.txt
25 or apexkeys.txt (so mappings specified by -k and -d are applied). Keys
26 specified in -e override any value for that app contained in the
27 apkcerts.txt file, or the container key for an APEX. Option may be
28 repeated to give multiple extra packages.
29
30 --extra_apex_payload_key <name=key>
31 Add a mapping for APEX package name to payload signing key, which will
32 override the default payload signing key in apexkeys.txt. Note that the
33 container key should be overridden via the `--extra_apks` flag above.
34 Option may be repeated for multiple APEXes.
Doug Zongkereef39442009-04-02 12:14:19 -070035
Tao Bao93c2a012018-06-19 12:19:35 -070036 --skip_apks_with_path_prefix <prefix>
37 Skip signing an APK if it has the matching prefix in its path. The prefix
38 should be matching the entry name, which has partition names in upper
39 case, e.g. "VENDOR/app/", or "SYSTEM_OTHER/preloads/". Option may be
40 repeated to give multiple prefixes.
41
Doug Zongkereef39442009-04-02 12:14:19 -070042 -k (--key_mapping) <src_key=dest_key>
43 Add a mapping from the key name as specified in apkcerts.txt (the
44 src_key) to the real key you wish to sign the package with
45 (dest_key). Option may be repeated to give multiple key
46 mappings.
47
48 -d (--default_key_mappings) <dir>
49 Set up the following key mappings:
50
Doug Zongker831840e2011-09-22 10:28:04 -070051 $devkey/devkey ==> $dir/releasekey
52 $devkey/testkey ==> $dir/releasekey
53 $devkey/media ==> $dir/media
54 $devkey/shared ==> $dir/shared
55 $devkey/platform ==> $dir/platform
56
57 where $devkey is the directory part of the value of
58 default_system_dev_certificate from the input target-files's
Dan Willemsen0ab1be62019-04-09 21:35:37 -070059 META/misc_info.txt. (Defaulting to "build/make/target/product/security"
Doug Zongker831840e2011-09-22 10:28:04 -070060 if the value is not present in misc_info.
Doug Zongkereef39442009-04-02 12:14:19 -070061
62 -d and -k options are added to the set of mappings in the order
63 in which they appear on the command line.
Doug Zongker8e931bf2009-04-06 15:21:45 -070064
65 -o (--replace_ota_keys)
Tao Baoa80ed222016-06-16 14:41:24 -070066 Replace the certificate (public key) used by OTA package verification
67 with the ones specified in the input target_files zip (in the
68 META/otakeys.txt file). Key remapping (-k and -d) is performed on the
69 keys. For A/B devices, the payload verification key will be replaced
70 as well. If there're multiple OTA keys, only the first one will be used
71 for payload verification.
Doug Zongker17aa9442009-04-17 10:15:58 -070072
Doug Zongkerae877012009-04-21 10:04:51 -070073 -t (--tag_changes) <+tag>,<-tag>,...
74 Comma-separated list of changes to make to the set of tags (in
75 the last component of the build fingerprint). Prefix each with
76 '+' or '-' to indicate whether that tag should be added or
77 removed. Changes are processed in the order they appear.
Doug Zongker831840e2011-09-22 10:28:04 -070078 Default value is "-test-keys,-dev-keys,+release-keys".
Doug Zongkerae877012009-04-21 10:04:51 -070079
Tao Bao8adcfd12016-06-17 17:01:22 -070080 --replace_verity_private_key <key>
81 Replace the private key used for verity signing. It expects a filename
82 WITHOUT the extension (e.g. verity_key).
83
84 --replace_verity_public_key <key>
85 Replace the certificate (public key) used for verity verification. The
86 key file replaces the one at BOOT/RAMDISK/verity_key (or ROOT/verity_key
87 for devices using system_root_image). It expects the key filename WITH
88 the extension (e.g. verity_key.pub).
89
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -070090 --replace_verity_keyid <path_to_X509_PEM_cert_file>
91 Replace the veritykeyid in BOOT/cmdline of input_target_file_zip
Tao Bao8adcfd12016-06-17 17:01:22 -070092 with keyid of the cert pointed by <path_to_X509_PEM_cert_file>.
Tao Bao639118f2017-06-19 15:48:02 -070093
Bowgo Tsai2fe786a2020-02-21 17:48:18 +080094 --remove_avb_public_keys <key1>,<key2>,...
95 Remove AVB public keys from the first-stage ramdisk. The key file to
96 remove is located at either of the following dirs:
97 - BOOT/RAMDISK/avb/ or
98 - BOOT/RAMDISK/first_stage_ramdisk/avb/
99 The second dir will be used for lookup if BOARD_USES_RECOVERY_AS_BOOT is
100 set to true.
101
Tao Baod6085d62019-05-06 12:55:42 -0700102 --avb_{boot,system,system_other,vendor,dtbo,vbmeta,vbmeta_system,
103 vbmeta_vendor}_algorithm <algorithm>
104 --avb_{boot,system,system_other,vendor,dtbo,vbmeta,vbmeta_system,
105 vbmeta_vendor}_key <key>
Tao Bao639118f2017-06-19 15:48:02 -0700106 Use the specified algorithm (e.g. SHA256_RSA4096) and the key to AVB-sign
107 the specified image. Otherwise it uses the existing values in info dict.
108
Tao Baod6085d62019-05-06 12:55:42 -0700109 --avb_{apex,boot,system,system_other,vendor,dtbo,vbmeta,vbmeta_system,
110 vbmeta_vendor}_extra_args <args>
Tao Bao639118f2017-06-19 15:48:02 -0700111 Specify any additional args that are needed to AVB-sign the image
112 (e.g. "--signing_helper /path/to/helper"). The args will be appended to
113 the existing ones in info dict.
Tianjie Xu88a759d2020-01-23 10:47:54 -0800114
Hongguang Chenf23364d2020-04-27 18:36:36 -0700115 --avb_extra_custom_image_key <partition=key>
116 --avb_extra_custom_image_algorithm <partition=algorithm>
117 Use the specified algorithm (e.g. SHA256_RSA4096) and the key to AVB-sign
118 the specified custom images mounted on the partition. Otherwise it uses
119 the existing values in info dict.
120
121 --avb_extra_custom_image_extra_args <partition=extra_args>
122 Specify any additional args that are needed to AVB-sign the custom images
123 mounted on the partition (e.g. "--signing_helper /path/to/helper"). The
124 args will be appended to the existing ones in info dict.
125
Bowgo Tsai27c39b02021-03-12 21:40:32 +0800126 --gki_signing_algorithm <algorithm>
127 --gki_signing_key <key>
128 Use the specified algorithm (e.g. SHA256_RSA4096) and the key to generate
129 'boot signature' in a v4 boot.img. Otherwise it uses the existing values
130 in info dict.
131
132 --gki_signing_extra_args <args>
133 Specify any additional args that are needed to generate 'boot signature'
134 (e.g. --prop foo:bar). The args will be appended to the existing ones
135 in info dict.
136
Tianjie Xu88a759d2020-01-23 10:47:54 -0800137 --android_jar_path <path>
138 Path to the android.jar to repack the apex file.
Bowgo Tsai2a781692021-10-13 17:39:33 +0800139
Melisa Carranza Zunigae6d4fb52022-03-07 14:56:26 +0100140 --sepolicy_key <key>
141 Optional flag that specifies the sepolicy signing key, defaults to payload_key for the sepolicy.apex.
142
143 --sepolicy_cert <cert>
144 Optional flag that specifies the sepolicy signing cert.
145
146 --fsverity_tool <path>
147 Optional flag that specifies the path to fsverity tool to sign SEPolicy, defaults to fsverity.
148
Bowgo Tsai2a781692021-10-13 17:39:33 +0800149 --allow_gsi_debug_sepolicy
150 Allow the existence of the file 'userdebug_plat_sepolicy.cil' under
151 (/system/system_ext|/system_ext)/etc/selinux.
152 If not set, error out when the file exists.
Doug Zongkereef39442009-04-02 12:14:19 -0700153"""
154
Tao Bao0c28d2d2017-12-24 10:37:38 -0800155from __future__ import print_function
Doug Zongkereef39442009-04-02 12:14:19 -0700156
Robert Craig817c5742013-04-19 10:59:22 -0400157import base64
Doug Zongker8e931bf2009-04-06 15:21:45 -0700158import copy
Robert Craig817c5742013-04-19 10:59:22 -0400159import errno
Narayan Kamatha07bf042017-08-14 14:49:21 +0100160import gzip
Tao Baobb733882019-07-24 23:31:19 -0700161import io
Tao Baoaa7e9932019-03-15 09:37:01 -0700162import itertools
Tao Baobadceb22019-03-15 09:33:43 -0700163import logging
Doug Zongkereef39442009-04-02 12:14:19 -0700164import os
165import re
Narayan Kamatha07bf042017-08-14 14:49:21 +0100166import shutil
Tao Bao9fdd00f2017-07-12 11:57:05 -0700167import stat
Doug Zongkereef39442009-04-02 12:14:19 -0700168import subprocess
Tao Bao0c28d2d2017-12-24 10:37:38 -0800169import sys
Doug Zongkereef39442009-04-02 12:14:19 -0700170import tempfile
171import zipfile
Tao Bao66472632017-12-04 17:16:36 -0800172from xml.etree import ElementTree
Doug Zongkereef39442009-04-02 12:14:19 -0700173
Doug Zongker3c84f562014-07-31 11:06:30 -0700174import add_img_to_target_files
Tao Baoaa7e9932019-03-15 09:37:01 -0700175import apex_utils
Doug Zongkereef39442009-04-02 12:14:19 -0700176import common
177
Tao Bao0c28d2d2017-12-24 10:37:38 -0800178
179if sys.hexversion < 0x02070000:
180 print("Python 2.7 or newer is required.", file=sys.stderr)
181 sys.exit(1)
182
183
Tao Baobadceb22019-03-15 09:33:43 -0700184logger = logging.getLogger(__name__)
185
Doug Zongkereef39442009-04-02 12:14:19 -0700186OPTIONS = common.OPTIONS
187
188OPTIONS.extra_apks = {}
Tao Baoaa7e9932019-03-15 09:37:01 -0700189OPTIONS.extra_apex_payload_keys = {}
Tao Bao93c2a012018-06-19 12:19:35 -0700190OPTIONS.skip_apks_with_path_prefix = set()
Doug Zongkereef39442009-04-02 12:14:19 -0700191OPTIONS.key_map = {}
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700192OPTIONS.rebuild_recovery = False
Doug Zongker8e931bf2009-04-06 15:21:45 -0700193OPTIONS.replace_ota_keys = False
Geremy Condraf19b3652014-07-29 17:54:54 -0700194OPTIONS.replace_verity_public_key = False
195OPTIONS.replace_verity_private_key = False
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700196OPTIONS.replace_verity_keyid = False
Bowgo Tsai2fe786a2020-02-21 17:48:18 +0800197OPTIONS.remove_avb_public_keys = None
Doug Zongker831840e2011-09-22 10:28:04 -0700198OPTIONS.tag_changes = ("-test-keys", "-dev-keys", "+release-keys")
Tao Bao639118f2017-06-19 15:48:02 -0700199OPTIONS.avb_keys = {}
200OPTIONS.avb_algorithms = {}
201OPTIONS.avb_extra_args = {}
Bowgo Tsai27c39b02021-03-12 21:40:32 +0800202OPTIONS.gki_signing_key = None
203OPTIONS.gki_signing_algorithm = None
204OPTIONS.gki_signing_extra_args = None
Tianjie Xu88a759d2020-01-23 10:47:54 -0800205OPTIONS.android_jar_path = None
Daniel Norman78554ea2021-09-14 10:29:38 -0700206OPTIONS.vendor_partitions = set()
207OPTIONS.vendor_otatools = None
Melisa Carranza Zunigae6d4fb52022-03-07 14:56:26 +0100208OPTIONS.sepolicy_key = None
209OPTIONS.sepolicy_cert = None
210OPTIONS.fsverity_tool = None
Bowgo Tsai2a781692021-10-13 17:39:33 +0800211OPTIONS.allow_gsi_debug_sepolicy = False
Doug Zongkereef39442009-04-02 12:14:19 -0700212
Tao Bao0c28d2d2017-12-24 10:37:38 -0800213
Tao Bao19b02fe2019-10-09 00:04:28 -0700214AVB_FOOTER_ARGS_BY_PARTITION = {
Tianjiebf0b8a82021-03-03 17:31:04 -0800215 'boot': 'avb_boot_add_hash_footer_args',
Devin Mooreafdd7c72021-12-13 22:04:08 +0000216 'init_boot': 'avb_init_boot_add_hash_footer_args',
Tianjiebf0b8a82021-03-03 17:31:04 -0800217 'dtbo': 'avb_dtbo_add_hash_footer_args',
218 'product': 'avb_product_add_hashtree_footer_args',
219 'recovery': 'avb_recovery_add_hash_footer_args',
220 'system': 'avb_system_add_hashtree_footer_args',
Ramji Jiyani13a41372022-01-27 07:05:08 +0000221 'system_dlkm': "avb_system_dlkm_add_hashtree_footer_args",
Tianjiebf0b8a82021-03-03 17:31:04 -0800222 'system_ext': 'avb_system_ext_add_hashtree_footer_args',
223 'system_other': 'avb_system_other_add_hashtree_footer_args',
224 'odm': 'avb_odm_add_hashtree_footer_args',
225 'odm_dlkm': 'avb_odm_dlkm_add_hashtree_footer_args',
226 'pvmfw': 'avb_pvmfw_add_hash_footer_args',
227 'vendor': 'avb_vendor_add_hashtree_footer_args',
228 'vendor_boot': 'avb_vendor_boot_add_hash_footer_args',
229 'vendor_dlkm': "avb_vendor_dlkm_add_hashtree_footer_args",
230 'vbmeta': 'avb_vbmeta_args',
231 'vbmeta_system': 'avb_vbmeta_system_args',
232 'vbmeta_vendor': 'avb_vbmeta_vendor_args',
Tao Bao19b02fe2019-10-09 00:04:28 -0700233}
234
235
Tianjiebf0b8a82021-03-03 17:31:04 -0800236# Check that AVB_FOOTER_ARGS_BY_PARTITION is in sync with AVB_PARTITIONS.
237for partition in common.AVB_PARTITIONS:
238 if partition not in AVB_FOOTER_ARGS_BY_PARTITION:
239 raise RuntimeError("Missing {} in AVB_FOOTER_ARGS".format(partition))
240
Daniel Norman78554ea2021-09-14 10:29:38 -0700241# Partitions that can be regenerated after signing using a separate
242# vendor otatools package.
243ALLOWED_VENDOR_PARTITIONS = set(["vendor", "odm"])
244
Tianjiebf0b8a82021-03-03 17:31:04 -0800245
Tianjie4d48d502021-06-11 17:03:43 -0700246def IsApexFile(filename):
247 return filename.endswith(".apex") or filename.endswith(".capex")
248
Melisa Carranza Zunigae6d4fb52022-03-07 14:56:26 +0100249def IsSepolicyApex(filename):
250 return filename.endswith(OPTIONS.sepolicy_name)
Tianjie4d48d502021-06-11 17:03:43 -0700251
252def GetApexFilename(filename):
253 name = os.path.basename(filename)
254 # Replace the suffix for compressed apex
255 if name.endswith(".capex"):
256 return name.replace(".capex", ".apex")
257 return name
258
259
Narayan Kamatha07bf042017-08-14 14:49:21 +0100260def GetApkCerts(certmap):
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800261 # apply the key remapping to the contents of the file
Tao Baoa3705452019-06-24 15:33:41 -0700262 for apk, cert in certmap.items():
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800263 certmap[apk] = OPTIONS.key_map.get(cert, cert)
264
265 # apply all the -e options, overriding anything in the file
Tao Baoa3705452019-06-24 15:33:41 -0700266 for apk, cert in OPTIONS.extra_apks.items():
Doug Zongkerdecf9952009-12-15 17:27:49 -0800267 if not cert:
268 cert = "PRESIGNED"
Doug Zongkerad88c7c2009-04-14 12:34:27 -0700269 certmap[apk] = OPTIONS.key_map.get(cert, cert)
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800270
Doug Zongkereef39442009-04-02 12:14:19 -0700271 return certmap
272
Melisa Carranza Zunigae6d4fb52022-03-07 14:56:26 +0100273def GetSepolicyKeys(keys_info):
274 """Gets SEPolicy signing keys applying overrides from command line options.
275
276 Args:
277 keys_info: A dict that maps from the SEPolicy APEX filename to a tuple of
278 (sepolicy_key, sepolicy_cert, fsverity_tool).
279
280 Returns:
281 A dict that contains the updated APEX key mapping, which should be used for
282 the current signing.
283 """
284 for name in keys_info:
285 (sepolicy_key, sepolicy_cert, fsverity_tool) = keys_info[name]
286 sepolicy_key = OPTIONS.sepolicy_key if OPTIONS.sepolicy_key else sepolicy_key
287 sepolicy_cert = OPTIONS.sepolicy_cert if OPTIONS.sepolicy_cert else sepolicy_cert
288 fsverity_tool = OPTIONS.fsverity_tool if OPTIONS.fsverity_tool else fsverity_tool
289 keys_info[name] = (sepolicy_key, sepolicy_cert, fsverity_tool)
290 return keys_info
Doug Zongkereef39442009-04-02 12:14:19 -0700291
Tao Baoaa7e9932019-03-15 09:37:01 -0700292def GetApexKeys(keys_info, key_map):
293 """Gets APEX payload and container signing keys by applying the mapping rules.
294
Tao Baoe1343992019-03-19 12:24:03 -0700295 Presigned payload / container keys will be set accordingly.
Tao Baoaa7e9932019-03-15 09:37:01 -0700296
297 Args:
298 keys_info: A dict that maps from APEX filenames to a tuple of (payload_key,
Jooyung Han8caba5e2021-10-27 03:58:09 +0900299 container_key, sign_tool).
Tao Baoaa7e9932019-03-15 09:37:01 -0700300 key_map: A dict that overrides the keys, specified via command-line input.
301
302 Returns:
303 A dict that contains the updated APEX key mapping, which should be used for
304 the current signing.
Tao Baof98fa102019-04-24 14:51:25 -0700305
306 Raises:
307 AssertionError: On invalid container / payload key overrides.
Tao Baoaa7e9932019-03-15 09:37:01 -0700308 """
309 # Apply all the --extra_apex_payload_key options to override the payload
310 # signing keys in the given keys_info.
311 for apex, key in OPTIONS.extra_apex_payload_keys.items():
Tao Baoe1343992019-03-19 12:24:03 -0700312 if not key:
313 key = 'PRESIGNED'
Tao Bao34223092019-07-11 11:52:52 -0700314 if apex not in keys_info:
315 logger.warning('Failed to find %s in target_files; Ignored', apex)
316 continue
Jooyung Han8caba5e2021-10-27 03:58:09 +0900317 keys_info[apex] = (key, keys_info[apex][1], keys_info[apex][2])
Tao Baoaa7e9932019-03-15 09:37:01 -0700318
319 # Apply the key remapping to container keys.
Jooyung Han8caba5e2021-10-27 03:58:09 +0900320 for apex, (payload_key, container_key, sign_tool) in keys_info.items():
321 keys_info[apex] = (payload_key, key_map.get(container_key, container_key), sign_tool)
Tao Baoaa7e9932019-03-15 09:37:01 -0700322
323 # Apply all the --extra_apks options to override the container keys.
324 for apex, key in OPTIONS.extra_apks.items():
325 # Skip non-APEX containers.
326 if apex not in keys_info:
327 continue
Tao Baoe1343992019-03-19 12:24:03 -0700328 if not key:
329 key = 'PRESIGNED'
Jooyung Han8caba5e2021-10-27 03:58:09 +0900330 keys_info[apex] = (keys_info[apex][0], key_map.get(key, key), keys_info[apex][2])
Tao Baoaa7e9932019-03-15 09:37:01 -0700331
Tao Baof98fa102019-04-24 14:51:25 -0700332 # A PRESIGNED container entails a PRESIGNED payload. Apply this to all the
333 # APEX key pairs. However, a PRESIGNED container with non-PRESIGNED payload
334 # (overridden via commandline) indicates a config error, which should not be
335 # allowed.
Jooyung Han8caba5e2021-10-27 03:58:09 +0900336 for apex, (payload_key, container_key, sign_tool) in keys_info.items():
Tao Baof98fa102019-04-24 14:51:25 -0700337 if container_key != 'PRESIGNED':
338 continue
339 if apex in OPTIONS.extra_apex_payload_keys:
340 payload_override = OPTIONS.extra_apex_payload_keys[apex]
341 assert payload_override == '', \
342 ("Invalid APEX key overrides: {} has PRESIGNED container but "
343 "non-PRESIGNED payload key {}").format(apex, payload_override)
344 if payload_key != 'PRESIGNED':
345 print(
346 "Setting {} payload as PRESIGNED due to PRESIGNED container".format(
347 apex))
Jooyung Han8caba5e2021-10-27 03:58:09 +0900348 keys_info[apex] = ('PRESIGNED', 'PRESIGNED', None)
Tao Baof98fa102019-04-24 14:51:25 -0700349
Tao Baoaa7e9932019-03-15 09:37:01 -0700350 return keys_info
351
352
Tao Bao93c2a012018-06-19 12:19:35 -0700353def GetApkFileInfo(filename, compressed_extension, skipped_prefixes):
Tao Bao11f955c2018-06-19 12:19:35 -0700354 """Returns the APK info based on the given filename.
355
356 Checks if the given filename (with path) looks like an APK file, by taking the
Tao Bao93c2a012018-06-19 12:19:35 -0700357 compressed extension into consideration. If it appears to be an APK file,
358 further checks if the APK file should be skipped when signing, based on the
359 given path prefixes.
Tao Bao11f955c2018-06-19 12:19:35 -0700360
361 Args:
362 filename: Path to the file.
363 compressed_extension: The extension string of compressed APKs (e.g. ".gz"),
364 or None if there's no compressed APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700365 skipped_prefixes: A set/list/tuple of the path prefixes to be skipped.
Tao Bao11f955c2018-06-19 12:19:35 -0700366
367 Returns:
Tao Bao93c2a012018-06-19 12:19:35 -0700368 (is_apk, is_compressed, should_be_skipped): is_apk indicates whether the
369 given filename is an APK file. is_compressed indicates whether the APK file
370 is compressed (only meaningful when is_apk is True). should_be_skipped
371 indicates whether the filename matches any of the given prefixes to be
372 skipped.
Tao Bao11f955c2018-06-19 12:19:35 -0700373
374 Raises:
Tao Bao93c2a012018-06-19 12:19:35 -0700375 AssertionError: On invalid compressed_extension or skipped_prefixes inputs.
Tao Bao11f955c2018-06-19 12:19:35 -0700376 """
377 assert compressed_extension is None or compressed_extension.startswith('.'), \
378 "Invalid compressed_extension arg: '{}'".format(compressed_extension)
379
Tao Bao93c2a012018-06-19 12:19:35 -0700380 # skipped_prefixes should be one of set/list/tuple types. Other types such as
381 # str shouldn't be accepted.
Tao Baobadceb22019-03-15 09:33:43 -0700382 assert isinstance(skipped_prefixes, (set, list, tuple)), \
383 "Invalid skipped_prefixes input type: {}".format(type(skipped_prefixes))
Tao Bao93c2a012018-06-19 12:19:35 -0700384
Tao Bao11f955c2018-06-19 12:19:35 -0700385 compressed_apk_extension = (
386 ".apk" + compressed_extension if compressed_extension else None)
387 is_apk = (filename.endswith(".apk") or
388 (compressed_apk_extension and
389 filename.endswith(compressed_apk_extension)))
390 if not is_apk:
Tao Bao93c2a012018-06-19 12:19:35 -0700391 return (False, False, False)
Tao Bao11f955c2018-06-19 12:19:35 -0700392
393 is_compressed = (compressed_apk_extension and
394 filename.endswith(compressed_apk_extension))
Tao Bao93c2a012018-06-19 12:19:35 -0700395 should_be_skipped = filename.startswith(tuple(skipped_prefixes))
396 return (True, is_compressed, should_be_skipped)
Tao Bao11f955c2018-06-19 12:19:35 -0700397
398
Tao Baoaa7e9932019-03-15 09:37:01 -0700399def CheckApkAndApexKeysAvailable(input_tf_zip, known_keys,
Tao Baoe1343992019-03-19 12:24:03 -0700400 compressed_extension, apex_keys):
Tao Baoaa7e9932019-03-15 09:37:01 -0700401 """Checks that all the APKs and APEXes have keys specified.
Tao Bao11f955c2018-06-19 12:19:35 -0700402
403 Args:
404 input_tf_zip: An open target_files zip file.
Tao Baoaa7e9932019-03-15 09:37:01 -0700405 known_keys: A set of APKs and APEXes that have known signing keys.
Tao Bao11f955c2018-06-19 12:19:35 -0700406 compressed_extension: The extension string of compressed APKs, such as
Tao Baoaa7e9932019-03-15 09:37:01 -0700407 '.gz', or None if there's no compressed APKs.
Tao Baoe1343992019-03-19 12:24:03 -0700408 apex_keys: A dict that contains the key mapping from APEX name to
Jooyung Han8caba5e2021-10-27 03:58:09 +0900409 (payload_key, container_key, sign_tool).
Tao Bao11f955c2018-06-19 12:19:35 -0700410
411 Raises:
Tao Baoaa7e9932019-03-15 09:37:01 -0700412 AssertionError: On finding unknown APKs and APEXes.
Tao Bao11f955c2018-06-19 12:19:35 -0700413 """
Tao Baoaa7e9932019-03-15 09:37:01 -0700414 unknown_files = []
Doug Zongkereb338ef2009-05-20 16:50:49 -0700415 for info in input_tf_zip.infolist():
Tianjie5bd03952021-02-18 23:02:36 -0800416 # Handle APEXes on all partitions
Tianjie4d48d502021-06-11 17:03:43 -0700417 if IsApexFile(info.filename):
418 name = GetApexFilename(info.filename)
Tao Baoaa7e9932019-03-15 09:37:01 -0700419 if name not in known_keys:
420 unknown_files.append(name)
421 continue
422
423 # And APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700424 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
425 info.filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
426 if not is_apk or should_be_skipped:
Tao Bao11f955c2018-06-19 12:19:35 -0700427 continue
Tao Baoaa7e9932019-03-15 09:37:01 -0700428
Tao Bao11f955c2018-06-19 12:19:35 -0700429 name = os.path.basename(info.filename)
430 if is_compressed:
431 name = name[:-len(compressed_extension)]
Tao Baoaa7e9932019-03-15 09:37:01 -0700432 if name not in known_keys:
433 unknown_files.append(name)
Tao Bao11f955c2018-06-19 12:19:35 -0700434
Tao Baoaa7e9932019-03-15 09:37:01 -0700435 assert not unknown_files, \
Tao Bao11f955c2018-06-19 12:19:35 -0700436 ("No key specified for:\n {}\n"
437 "Use '-e <apkname>=' to specify a key (which may be an empty string to "
Tao Baoaa7e9932019-03-15 09:37:01 -0700438 "not sign this apk).".format("\n ".join(unknown_files)))
Doug Zongkereb338ef2009-05-20 16:50:49 -0700439
Tao Baoe1343992019-03-19 12:24:03 -0700440 # For all the APEXes, double check that we won't have an APEX that has only
Tao Baof98fa102019-04-24 14:51:25 -0700441 # one of the payload / container keys set. Note that non-PRESIGNED container
442 # with PRESIGNED payload could be allowed but currently unsupported. It would
443 # require changing SignApex implementation.
Tao Baoe1343992019-03-19 12:24:03 -0700444 if not apex_keys:
445 return
446
447 invalid_apexes = []
448 for info in input_tf_zip.infolist():
Tianjie4d48d502021-06-11 17:03:43 -0700449 if not IsApexFile(info.filename):
Tao Baoe1343992019-03-19 12:24:03 -0700450 continue
451
Tianjie4d48d502021-06-11 17:03:43 -0700452 name = GetApexFilename(info.filename)
453
Jooyung Han8caba5e2021-10-27 03:58:09 +0900454 (payload_key, container_key, _) = apex_keys[name]
Tao Baoe1343992019-03-19 12:24:03 -0700455 if ((payload_key in common.SPECIAL_CERT_STRINGS and
456 container_key not in common.SPECIAL_CERT_STRINGS) or
457 (payload_key not in common.SPECIAL_CERT_STRINGS and
458 container_key in common.SPECIAL_CERT_STRINGS)):
459 invalid_apexes.append(
460 "{}: payload_key {}, container_key {}".format(
461 name, payload_key, container_key))
462
463 assert not invalid_apexes, \
464 "Invalid APEX keys specified:\n {}\n".format(
465 "\n ".join(invalid_apexes))
466
Doug Zongkereb338ef2009-05-20 16:50:49 -0700467
Narayan Kamatha07bf042017-08-14 14:49:21 +0100468def SignApk(data, keyname, pw, platform_api_level, codename_to_api_level_map,
Oleg Aravin8046cb02020-06-02 16:02:38 -0700469 is_compressed, apk_name):
470 unsigned = tempfile.NamedTemporaryFile(suffix='_' + apk_name)
Doug Zongkereef39442009-04-02 12:14:19 -0700471 unsigned.write(data)
472 unsigned.flush()
473
Narayan Kamatha07bf042017-08-14 14:49:21 +0100474 if is_compressed:
475 uncompressed = tempfile.NamedTemporaryFile()
Tao Bao0c28d2d2017-12-24 10:37:38 -0800476 with gzip.open(unsigned.name, "rb") as in_file, \
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400477 open(uncompressed.name, "wb") as out_file:
Narayan Kamatha07bf042017-08-14 14:49:21 +0100478 shutil.copyfileobj(in_file, out_file)
479
480 # Finally, close the "unsigned" file (which is gzip compressed), and then
481 # replace it with the uncompressed version.
482 #
483 # TODO(narayan): All this nastiness can be avoided if python 3.2 is in use,
484 # we could just gzip / gunzip in-memory buffers instead.
485 unsigned.close()
486 unsigned = uncompressed
487
Oleg Aravin8046cb02020-06-02 16:02:38 -0700488 signed = tempfile.NamedTemporaryFile(suffix='_' + apk_name)
Doug Zongkereef39442009-04-02 12:14:19 -0700489
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800490 # For pre-N builds, don't upgrade to SHA-256 JAR signatures based on the APK's
491 # minSdkVersion to avoid increasing incremental OTA update sizes. If an APK
492 # didn't change, we don't want its signature to change due to the switch
493 # from SHA-1 to SHA-256.
494 # By default, APK signer chooses SHA-256 signatures if the APK's minSdkVersion
495 # is 18 or higher. For pre-N builds we disable this mechanism by pretending
496 # that the APK's minSdkVersion is 1.
497 # For N+ builds, we let APK signer rely on the APK's minSdkVersion to
498 # determine whether to use SHA-256.
499 min_api_level = None
500 if platform_api_level > 23:
501 # Let APK signer choose whether to use SHA-1 or SHA-256, based on the APK's
502 # minSdkVersion attribute
503 min_api_level = None
504 else:
505 # Force APK signer to use SHA-1
506 min_api_level = 1
507
508 common.SignFile(unsigned.name, signed.name, keyname, pw,
Tao Bao0c28d2d2017-12-24 10:37:38 -0800509 min_api_level=min_api_level,
510 codename_to_api_level_map=codename_to_api_level_map)
Doug Zongkereef39442009-04-02 12:14:19 -0700511
Tao Bao0c28d2d2017-12-24 10:37:38 -0800512 data = None
Narayan Kamatha07bf042017-08-14 14:49:21 +0100513 if is_compressed:
514 # Recompress the file after it has been signed.
515 compressed = tempfile.NamedTemporaryFile()
Tao Bao0c28d2d2017-12-24 10:37:38 -0800516 with open(signed.name, "rb") as in_file, \
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400517 gzip.open(compressed.name, "wb") as out_file:
Narayan Kamatha07bf042017-08-14 14:49:21 +0100518 shutil.copyfileobj(in_file, out_file)
519
520 data = compressed.read()
521 compressed.close()
522 else:
523 data = signed.read()
524
Doug Zongkereef39442009-04-02 12:14:19 -0700525 unsigned.close()
526 signed.close()
527
528 return data
529
Tianjie5bd03952021-02-18 23:02:36 -0800530
Kelvin Zhang119f2792021-02-10 12:45:24 -0500531def IsBuildPropFile(filename):
532 return filename in (
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400533 "SYSTEM/etc/prop.default",
534 "BOOT/RAMDISK/prop.default",
535 "RECOVERY/RAMDISK/prop.default",
Kelvin Zhang119f2792021-02-10 12:45:24 -0500536
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400537 "VENDOR_BOOT/RAMDISK/default.prop",
538 "VENDOR_BOOT/RAMDISK/prop.default",
Kelvin Zhang119f2792021-02-10 12:45:24 -0500539
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400540 # ROOT/default.prop is a legacy path, but may still exist for upgrading
541 # devices that don't support `property_overrides_split_enabled`.
542 "ROOT/default.prop",
Kelvin Zhang119f2792021-02-10 12:45:24 -0500543
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400544 # RECOVERY/RAMDISK/default.prop is a legacy path, but will always exist
545 # as a symlink in the current code. So it's a no-op here. Keeping the
546 # path here for clarity.
547 "RECOVERY/RAMDISK/default.prop") or filename.endswith("build.prop")
Doug Zongkereef39442009-04-02 12:14:19 -0700548
Tianjie5bd03952021-02-18 23:02:36 -0800549
Doug Zongker412c02f2014-02-13 10:58:24 -0800550def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -0700551 apk_keys, apex_keys, key_passwords,
552 platform_api_level, codename_to_api_level_map,
Melisa Carranza Zunigae6d4fb52022-03-07 14:56:26 +0100553 compressed_extension, sepolicy_keys):
Tao Bao93c2a012018-06-19 12:19:35 -0700554 # maxsize measures the maximum filename length, including the ones to be
555 # skipped.
Bowgo Tsai8d4b7242022-01-04 15:15:35 +0800556 try:
557 maxsize = max(
558 [len(os.path.basename(i.filename)) for i in input_tf_zip.infolist()
559 if GetApkFileInfo(i.filename, compressed_extension, [])[0]])
560 except ValueError:
561 # Sets this to zero for targets without APK files, e.g., gki_arm64.
562 maxsize = 0
563
Tao Baoa80ed222016-06-16 14:41:24 -0700564 system_root_image = misc_info.get("system_root_image") == "true"
Doug Zongker412c02f2014-02-13 10:58:24 -0800565
Doug Zongkereef39442009-04-02 12:14:19 -0700566 for info in input_tf_zip.infolist():
Tao Bao11f955c2018-06-19 12:19:35 -0700567 filename = info.filename
568 if filename.startswith("IMAGES/"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700569 continue
Doug Zongker3c84f562014-07-31 11:06:30 -0700570
Tao Bao04808502019-07-25 23:11:41 -0700571 # Skip OTA-specific images (e.g. split super images), which will be
572 # re-generated during signing.
Tao Bao33bf2682019-01-11 12:37:35 -0800573 if filename.startswith("OTA/") and filename.endswith(".img"):
574 continue
575
Tao Bao11f955c2018-06-19 12:19:35 -0700576 data = input_tf_zip.read(filename)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700577 out_info = copy.copy(info)
Tao Bao93c2a012018-06-19 12:19:35 -0700578 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
579 filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
580
581 if is_apk and should_be_skipped:
582 # Copy skipped APKs verbatim.
583 print(
584 "NOT signing: %s\n"
585 " (skipped due to matching prefix)" % (filename,))
586 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker412c02f2014-02-13 10:58:24 -0800587
Tao Baof2cffbd2015-07-22 12:33:18 -0700588 # Sign APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700589 elif is_apk:
Tao Bao11f955c2018-06-19 12:19:35 -0700590 name = os.path.basename(filename)
Narayan Kamatha07bf042017-08-14 14:49:21 +0100591 if is_compressed:
592 name = name[:-len(compressed_extension)]
593
Tao Baoaa7e9932019-03-15 09:37:01 -0700594 key = apk_keys[name]
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800595 if key not in common.SPECIAL_CERT_STRINGS:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800596 print(" signing: %-*s (%s)" % (maxsize, name, key))
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800597 signed_data = SignApk(data, key, key_passwords[key], platform_api_level,
Oleg Aravin8046cb02020-06-02 16:02:38 -0700598 codename_to_api_level_map, is_compressed, name)
Tao Bao2ed665a2015-04-01 11:21:55 -0700599 common.ZipWriteStr(output_tf_zip, out_info, signed_data)
Doug Zongkereef39442009-04-02 12:14:19 -0700600 else:
601 # an APK we're not supposed to sign.
Tao Bao93c2a012018-06-19 12:19:35 -0700602 print(
603 "NOT signing: %s\n"
604 " (skipped due to special cert string)" % (name,))
Tao Bao2ed665a2015-04-01 11:21:55 -0700605 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoa80ed222016-06-16 14:41:24 -0700606
Tianjie5bd03952021-02-18 23:02:36 -0800607 # Sign bundled APEX files on all partitions
Tianjie4d48d502021-06-11 17:03:43 -0700608 elif IsApexFile(filename):
609 name = GetApexFilename(filename)
610
Jooyung Han8caba5e2021-10-27 03:58:09 +0900611 payload_key, container_key, sign_tool = apex_keys[name]
Tao Baoaa7e9932019-03-15 09:37:01 -0700612
Tao Baoe1343992019-03-19 12:24:03 -0700613 # We've asserted not having a case with only one of them PRESIGNED.
614 if (payload_key not in common.SPECIAL_CERT_STRINGS and
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400615 container_key not in common.SPECIAL_CERT_STRINGS):
Tao Baoe1343992019-03-19 12:24:03 -0700616 print(" signing: %-*s container (%s)" % (
617 maxsize, name, container_key))
618 print(" : %-*s payload (%s)" % (
619 maxsize, name, payload_key))
Tao Baoaa7e9932019-03-15 09:37:01 -0700620
Melisa Carranza Zunigae6d4fb52022-03-07 14:56:26 +0100621 sepolicy_key = None
622 sepolicy_cert = None
623 fsverity_tool = None
624
625 if IsSepolicyApex(name):
626 (sepolicy_key, sepolicy_cert, fsverity_tool) = sepolicy_keys[name]
627 print(" : %-*s sepolicy key (%s)" % (
628 maxsize, name, sepolicy_key))
629 print(" : %-*s sepolicy cert (%s)" % (
630 maxsize, name, sepolicy_cert))
631
Tao Baoe7354ba2019-05-09 16:54:15 -0700632 signed_apex = apex_utils.SignApex(
Tao Bao1ac886e2019-06-26 11:58:22 -0700633 misc_info['avb_avbtool'],
Tao Baoe1343992019-03-19 12:24:03 -0700634 data,
635 payload_key,
636 container_key,
Oleh Cherpake555ab12020-10-05 17:04:59 +0300637 key_passwords,
Tianjie Xu88a759d2020-01-23 10:47:54 -0800638 apk_keys,
Tao Baoe1343992019-03-19 12:24:03 -0700639 codename_to_api_level_map,
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400640 no_hashtree=None, # Let apex_util determine if hash tree is needed
Jooyung Han8caba5e2021-10-27 03:58:09 +0900641 signing_args=OPTIONS.avb_extra_args.get('apex'),
Melisa Carranza Zunigae6d4fb52022-03-07 14:56:26 +0100642 sign_tool=sign_tool,
643 is_sepolicy=IsSepolicyApex(name),
644 sepolicy_key=sepolicy_key,
645 sepolicy_cert=sepolicy_cert,
646 fsverity_tool=fsverity_tool)
Tao Baoe1343992019-03-19 12:24:03 -0700647 common.ZipWrite(output_tf_zip, signed_apex, filename)
Tao Baoaa7e9932019-03-15 09:37:01 -0700648
Tao Baoe1343992019-03-19 12:24:03 -0700649 else:
650 print(
651 "NOT signing: %s\n"
652 " (skipped due to special cert string)" % (name,))
653 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoaa7e9932019-03-15 09:37:01 -0700654
Tao Baoa80ed222016-06-16 14:41:24 -0700655 # System properties.
Kelvin Zhang119f2792021-02-10 12:45:24 -0500656 elif IsBuildPropFile(filename):
Tao Bao11f955c2018-06-19 12:19:35 -0700657 print("Rewriting %s:" % (filename,))
Hung-ying Tyan7eb6a922017-05-01 21:56:26 +0800658 if stat.S_ISLNK(info.external_attr >> 16):
659 new_data = data
660 else:
Tao Baoa3705452019-06-24 15:33:41 -0700661 new_data = RewriteProps(data.decode())
Tao Bao2ed665a2015-04-01 11:21:55 -0700662 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700663
Tao Bao66472632017-12-04 17:16:36 -0800664 # Replace the certs in *mac_permissions.xml (there could be multiple, such
Inseob Kime7b222a2021-12-21 15:57:03 +0900665 # as {system,vendor}/etc/selinux/{plat,vendor}_mac_permissions.xml).
Tao Bao11f955c2018-06-19 12:19:35 -0700666 elif filename.endswith("mac_permissions.xml"):
667 print("Rewriting %s with new keys." % (filename,))
Tao Baoa3705452019-06-24 15:33:41 -0700668 new_data = ReplaceCerts(data.decode())
Tao Bao2ed665a2015-04-01 11:21:55 -0700669 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700670
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700671 # Ask add_img_to_target_files to rebuild the recovery patch if needed.
Tao Bao11f955c2018-06-19 12:19:35 -0700672 elif filename in ("SYSTEM/recovery-from-boot.p",
Robin Leeda427de2020-01-03 19:16:32 +0100673 "VENDOR/recovery-from-boot.p",
674
Tao Bao11f955c2018-06-19 12:19:35 -0700675 "SYSTEM/etc/recovery.img",
Robin Leeda427de2020-01-03 19:16:32 +0100676 "VENDOR/etc/recovery.img",
677
678 "SYSTEM/bin/install-recovery.sh",
679 "VENDOR/bin/install-recovery.sh"):
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700680 OPTIONS.rebuild_recovery = True
Tao Baoa80ed222016-06-16 14:41:24 -0700681
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700682 # Don't copy OTA certs if we're replacing them.
Tianjie Xu2df23d72019-10-15 18:06:25 -0700683 # Replacement of update-payload-key.pub.pem was removed in b/116660991.
Kelvin Zhang9f781ff2021-02-11 19:10:44 -0500684 elif OPTIONS.replace_ota_keys and filename.endswith("/otacerts.zip"):
Doug Zongker412c02f2014-02-13 10:58:24 -0800685 pass
Tao Baoa80ed222016-06-16 14:41:24 -0700686
Tao Bao46a59992017-06-05 11:55:16 -0700687 # Skip META/misc_info.txt since we will write back the new values later.
Tao Bao11f955c2018-06-19 12:19:35 -0700688 elif filename == "META/misc_info.txt":
Geremy Condraf19b3652014-07-29 17:54:54 -0700689 pass
Tao Bao8adcfd12016-06-17 17:01:22 -0700690
691 # Skip verity public key if we will replace it.
Michael Runge947894f2014-10-14 20:58:38 -0700692 elif (OPTIONS.replace_verity_public_key and
Tao Bao11f955c2018-06-19 12:19:35 -0700693 filename in ("BOOT/RAMDISK/verity_key",
694 "ROOT/verity_key")):
Geremy Condraf19b3652014-07-29 17:54:54 -0700695 pass
Bowgo Tsai2fe786a2020-02-21 17:48:18 +0800696 elif (OPTIONS.remove_avb_public_keys and
697 (filename.startswith("BOOT/RAMDISK/avb/") or
698 filename.startswith("BOOT/RAMDISK/first_stage_ramdisk/avb/"))):
Kelvin Zhang0876c412020-06-23 15:06:58 -0400699 matched_removal = False
700 for key_to_remove in OPTIONS.remove_avb_public_keys:
701 if filename.endswith(key_to_remove):
702 matched_removal = True
703 print("Removing AVB public key from ramdisk: %s" % filename)
704 break
705 if not matched_removal:
706 # Copy it verbatim if we don't want to remove it.
707 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoa80ed222016-06-16 14:41:24 -0700708
Tao Bao8adcfd12016-06-17 17:01:22 -0700709 # Skip verity keyid (for system_root_image use) if we will replace it.
Tao Bao11f955c2018-06-19 12:19:35 -0700710 elif OPTIONS.replace_verity_keyid and filename == "BOOT/cmdline":
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700711 pass
712
Tianjiebbde59f2021-05-03 21:18:56 -0700713 # Skip the vbmeta digest as we will recalculate it.
714 elif filename == "META/vbmeta_digest.txt":
715 pass
716
Tianjie Xu4f099002016-08-11 18:04:27 -0700717 # Skip the care_map as we will regenerate the system/vendor images.
Kelvin Zhang0876c412020-06-23 15:06:58 -0400718 elif filename in ["META/care_map.pb", "META/care_map.txt"]:
Tianjie Xu4f099002016-08-11 18:04:27 -0700719 pass
720
Kelvin Zhang5f0fcee2021-01-19 15:30:46 -0500721 # Skip apex_info.pb because we sign/modify apexes
722 elif filename == "META/apex_info.pb":
723 pass
724
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800725 # Updates system_other.avbpubkey in /product/etc/.
726 elif filename in (
727 "PRODUCT/etc/security/avb/system_other.avbpubkey",
Bowgo Tsai2a781692021-10-13 17:39:33 +0800728 "SYSTEM/product/etc/security/avb/system_other.avbpubkey"):
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800729 # Only update system_other's public key, if the corresponding signing
730 # key is specified via --avb_system_other_key.
731 signing_key = OPTIONS.avb_keys.get("system_other")
732 if signing_key:
Tao Bao1ac886e2019-06-26 11:58:22 -0700733 public_key = common.ExtractAvbPublicKey(
734 misc_info['avb_avbtool'], signing_key)
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800735 print(" Rewriting AVB public key of system_other in /product")
736 common.ZipWrite(output_tf_zip, public_key, filename)
737
Andrew Scullbbc930b2022-02-17 22:34:27 +0000738 # Updates pvmfw embedded public key with the virt APEX payload key.
739 elif filename == "PREBUILT_IMAGES/pvmfw.img":
740 # Find the name of the virt APEX in the target files.
741 namelist = input_tf_zip.namelist()
742 apex_gen = (GetApexFilename(f) for f in namelist if IsApexFile(f))
743 virt_apex_re = re.compile("^com\.([^\.]+\.)?android\.virt\.apex$")
744 virt_apex = next((a for a in apex_gen if virt_apex_re.match(a)), None)
745 if not virt_apex:
746 print("Removing %s from ramdisk: virt APEX not found" % filename)
747 else:
748 print("Replacing %s embedded key with %s key" % (filename, virt_apex))
749 # Get the current and new embedded keys.
750 payload_key, container_key, sign_tool = apex_keys[virt_apex]
751 new_pubkey_path = common.ExtractAvbPublicKey(
752 misc_info['avb_avbtool'], payload_key)
753 with open(new_pubkey_path, 'rb') as f:
754 new_pubkey = f.read()
755 pubkey_info = copy.copy(
756 input_tf_zip.getinfo("PREBUILT_IMAGES/pvmfw_embedded.avbpubkey"))
757 old_pubkey = input_tf_zip.read(pubkey_info.filename)
758 # Validate the keys and image.
759 if len(old_pubkey) != len(new_pubkey):
760 raise common.ExternalError("pvmfw embedded public key size mismatch")
761 pos = data.find(old_pubkey)
762 if pos == -1:
763 raise common.ExternalError("pvmfw embedded public key not found")
764 # Replace the key and copy new files.
765 new_data = data[:pos] + new_pubkey + data[pos+len(old_pubkey):]
766 common.ZipWriteStr(output_tf_zip, out_info, new_data)
767 common.ZipWriteStr(output_tf_zip, pubkey_info, new_pubkey)
768 elif filename == "PREBUILT_IMAGES/pvmfw_embedded.avbpubkey":
769 pass
770
Bowgo Tsai78369eb2019-04-23 12:28:44 +0800771 # Should NOT sign boot-debug.img.
772 elif filename in (
773 "BOOT/RAMDISK/force_debuggable",
Bowgo Tsai2a781692021-10-13 17:39:33 +0800774 "BOOT/RAMDISK/first_stage_ramdisk/force_debuggable"):
Bowgo Tsai78369eb2019-04-23 12:28:44 +0800775 raise common.ExternalError("debuggable boot.img cannot be signed")
776
Bowgo Tsai2a781692021-10-13 17:39:33 +0800777 # Should NOT sign userdebug sepolicy file.
778 elif filename in (
779 "SYSTEM_EXT/etc/selinux/userdebug_plat_sepolicy.cil",
780 "SYSTEM/system_ext/etc/selinux/userdebug_plat_sepolicy.cil"):
781 if not OPTIONS.allow_gsi_debug_sepolicy:
782 raise common.ExternalError("debug sepolicy shouldn't be included")
783 else:
784 # Copy it verbatim if we allow the file to exist.
785 common.ZipWriteStr(output_tf_zip, out_info, data)
786
Tao Baoa80ed222016-06-16 14:41:24 -0700787 # A non-APK file; copy it verbatim.
Doug Zongkereef39442009-04-02 12:14:19 -0700788 else:
Tao Bao2ed665a2015-04-01 11:21:55 -0700789 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700790
Doug Zongker412c02f2014-02-13 10:58:24 -0800791 if OPTIONS.replace_ota_keys:
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700792 ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info)
Doug Zongker412c02f2014-02-13 10:58:24 -0800793
Tao Bao46a59992017-06-05 11:55:16 -0700794 # Replace the keyid string in misc_info dict.
Tao Bao8adcfd12016-06-17 17:01:22 -0700795 if OPTIONS.replace_verity_private_key:
Tao Bao46a59992017-06-05 11:55:16 -0700796 ReplaceVerityPrivateKey(misc_info, OPTIONS.replace_verity_private_key[1])
Tao Bao8adcfd12016-06-17 17:01:22 -0700797
798 if OPTIONS.replace_verity_public_key:
Tao Baoc9981932019-09-16 12:10:43 -0700799 # Replace the one in root dir in system.img.
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700800 ReplaceVerityPublicKey(
Tao Baoc9981932019-09-16 12:10:43 -0700801 output_tf_zip, 'ROOT/verity_key', OPTIONS.replace_verity_public_key[1])
802
803 if not system_root_image:
804 # Additionally replace the copy in ramdisk if not using system-as-root.
805 ReplaceVerityPublicKey(
806 output_tf_zip,
807 'BOOT/RAMDISK/verity_key',
808 OPTIONS.replace_verity_public_key[1])
Tao Bao8adcfd12016-06-17 17:01:22 -0700809
810 # Replace the keyid string in BOOT/cmdline.
811 if OPTIONS.replace_verity_keyid:
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700812 ReplaceVerityKeyId(input_tf_zip, output_tf_zip,
813 OPTIONS.replace_verity_keyid[1])
Doug Zongker412c02f2014-02-13 10:58:24 -0800814
Tao Bao639118f2017-06-19 15:48:02 -0700815 # Replace the AVB signing keys, if any.
816 ReplaceAvbSigningKeys(misc_info)
817
Tao Bao19b02fe2019-10-09 00:04:28 -0700818 # Rewrite the props in AVB signing args.
819 if misc_info.get('avb_enable') == 'true':
820 RewriteAvbProps(misc_info)
821
Bowgo Tsai27c39b02021-03-12 21:40:32 +0800822 # Replace the GKI signing key for boot.img, if any.
823 ReplaceGkiSigningKey(misc_info)
824
Tao Bao46a59992017-06-05 11:55:16 -0700825 # Write back misc_info with the latest values.
826 ReplaceMiscInfoTxt(input_tf_zip, output_tf_zip, misc_info)
827
Doug Zongker8e931bf2009-04-06 15:21:45 -0700828
Robert Craig817c5742013-04-19 10:59:22 -0400829def ReplaceCerts(data):
Tao Bao66472632017-12-04 17:16:36 -0800830 """Replaces all the occurences of X.509 certs with the new ones.
Robert Craig817c5742013-04-19 10:59:22 -0400831
Tao Bao66472632017-12-04 17:16:36 -0800832 The mapping info is read from OPTIONS.key_map. Non-existent certificate will
833 be skipped. After the replacement, it additionally checks for duplicate
834 entries, which would otherwise fail the policy loading code in
835 frameworks/base/services/core/java/com/android/server/pm/SELinuxMMAC.java.
836
837 Args:
838 data: Input string that contains a set of X.509 certs.
839
840 Returns:
841 A string after the replacement.
842
843 Raises:
844 AssertionError: On finding duplicate entries.
845 """
Tao Baoa3705452019-06-24 15:33:41 -0700846 for old, new in OPTIONS.key_map.items():
Tao Bao66472632017-12-04 17:16:36 -0800847 if OPTIONS.verbose:
848 print(" Replacing %s.x509.pem with %s.x509.pem" % (old, new))
849
850 try:
851 with open(old + ".x509.pem") as old_fp:
852 old_cert16 = base64.b16encode(
Tao Baoa3705452019-06-24 15:33:41 -0700853 common.ParseCertificate(old_fp.read())).decode().lower()
Tao Bao66472632017-12-04 17:16:36 -0800854 with open(new + ".x509.pem") as new_fp:
855 new_cert16 = base64.b16encode(
Tao Baoa3705452019-06-24 15:33:41 -0700856 common.ParseCertificate(new_fp.read())).decode().lower()
Tao Bao66472632017-12-04 17:16:36 -0800857 except IOError as e:
858 if OPTIONS.verbose or e.errno != errno.ENOENT:
859 print(" Error accessing %s: %s.\nSkip replacing %s.x509.pem with "
860 "%s.x509.pem." % (e.filename, e.strerror, old, new))
861 continue
862
863 # Only match entire certs.
864 pattern = "\\b" + old_cert16 + "\\b"
865 (data, num) = re.subn(pattern, new_cert16, data, flags=re.IGNORECASE)
866
867 if OPTIONS.verbose:
868 print(" Replaced %d occurence(s) of %s.x509.pem with %s.x509.pem" % (
869 num, old, new))
870
871 # Verify that there're no duplicate entries after the replacement. Note that
872 # it's only checking entries with global seinfo at the moment (i.e. ignoring
873 # the ones with inner packages). (Bug: 69479366)
874 root = ElementTree.fromstring(data)
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400875 signatures = [signer.attrib['signature']
876 for signer in root.findall('signer')]
Tao Bao66472632017-12-04 17:16:36 -0800877 assert len(signatures) == len(set(signatures)), \
878 "Found duplicate entries after cert replacement: {}".format(data)
Robert Craig817c5742013-04-19 10:59:22 -0400879
880 return data
881
882
Doug Zongkerc09abc82010-01-11 13:09:15 -0800883def EditTags(tags):
Tao Baoa7054ee2017-12-08 14:42:16 -0800884 """Applies the edits to the tag string as specified in OPTIONS.tag_changes.
885
886 Args:
887 tags: The input string that contains comma-separated tags.
888
889 Returns:
890 The updated tags (comma-separated and sorted).
891 """
Doug Zongkerc09abc82010-01-11 13:09:15 -0800892 tags = set(tags.split(","))
893 for ch in OPTIONS.tag_changes:
894 if ch[0] == "-":
895 tags.discard(ch[1:])
896 elif ch[0] == "+":
897 tags.add(ch[1:])
898 return ",".join(sorted(tags))
899
900
Tao Baoa7054ee2017-12-08 14:42:16 -0800901def RewriteProps(data):
902 """Rewrites the system properties in the given string.
903
904 Each property is expected in 'key=value' format. The properties that contain
905 build tags (i.e. test-keys, dev-keys) will be updated accordingly by calling
906 EditTags().
907
908 Args:
909 data: Input string, separated by newlines.
910
911 Returns:
912 The string with modified properties.
913 """
Doug Zongker17aa9442009-04-17 10:15:58 -0700914 output = []
915 for line in data.split("\n"):
916 line = line.strip()
917 original_line = line
Michael Rungedc2661a2014-06-03 14:43:11 -0700918 if line and line[0] != '#' and "=" in line:
Doug Zongker17aa9442009-04-17 10:15:58 -0700919 key, value = line.split("=", 1)
Magnus Strandh234f4b42019-05-01 23:09:30 +0200920 if (key.startswith("ro.") and
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400921 key.endswith((".build.fingerprint", ".build.thumbprint"))):
Doug Zongkerc09abc82010-01-11 13:09:15 -0800922 pieces = value.split("/")
923 pieces[-1] = EditTags(pieces[-1])
924 value = "/".join(pieces)
Tao Baocb7ff772015-09-11 15:27:56 -0700925 elif key == "ro.bootimage.build.fingerprint":
926 pieces = value.split("/")
927 pieces[-1] = EditTags(pieces[-1])
928 value = "/".join(pieces)
Doug Zongker17aa9442009-04-17 10:15:58 -0700929 elif key == "ro.build.description":
Doug Zongkerc09abc82010-01-11 13:09:15 -0800930 pieces = value.split(" ")
Stefen Wakefield4260fc12021-03-23 04:58:22 -0500931 assert pieces[-1].endswith("-keys")
Doug Zongkerc09abc82010-01-11 13:09:15 -0800932 pieces[-1] = EditTags(pieces[-1])
933 value = " ".join(pieces)
Magnus Strandh234f4b42019-05-01 23:09:30 +0200934 elif key.startswith("ro.") and key.endswith(".build.tags"):
Doug Zongkerc09abc82010-01-11 13:09:15 -0800935 value = EditTags(value)
Doug Zongkera8608a72013-07-23 11:51:04 -0700936 elif key == "ro.build.display.id":
937 # change, eg, "JWR66N dev-keys" to "JWR66N"
938 value = value.split()
Michael Rungedc2661a2014-06-03 14:43:11 -0700939 if len(value) > 1 and value[-1].endswith("-keys"):
Andrew Boie73d5abb2013-12-11 12:42:03 -0800940 value.pop()
941 value = " ".join(value)
Doug Zongkerc09abc82010-01-11 13:09:15 -0800942 line = key + "=" + value
Doug Zongker17aa9442009-04-17 10:15:58 -0700943 if line != original_line:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800944 print(" replace: ", original_line)
945 print(" with: ", line)
Doug Zongker17aa9442009-04-17 10:15:58 -0700946 output.append(line)
947 return "\n".join(output) + "\n"
948
949
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700950def WriteOtacerts(output_zip, filename, keys):
951 """Constructs a zipfile from given keys; and writes it to output_zip.
952
953 Args:
954 output_zip: The output target_files zip.
955 filename: The archive name in the output zip.
956 keys: A list of public keys to use during OTA package verification.
957 """
Tao Baobb733882019-07-24 23:31:19 -0700958 temp_file = io.BytesIO()
Kelvin Zhang928c2342020-09-22 16:15:57 -0400959 certs_zip = zipfile.ZipFile(temp_file, "w", allowZip64=True)
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700960 for k in keys:
961 common.ZipWrite(certs_zip, k)
962 common.ZipClose(certs_zip)
963 common.ZipWriteStr(output_zip, filename, temp_file.getvalue())
964
965
Doug Zongker831840e2011-09-22 10:28:04 -0700966def ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info):
Doug Zongker8e931bf2009-04-06 15:21:45 -0700967 try:
968 keylist = input_tf_zip.read("META/otakeys.txt").split()
969 except KeyError:
T.R. Fullharta28acc62013-03-18 10:31:26 -0700970 raise common.ExternalError("can't read META/otakeys.txt from input")
Doug Zongker8e931bf2009-04-06 15:21:45 -0700971
Jacky Liubeb0b692021-12-29 16:29:05 +0800972 extra_ota_keys_info = misc_info.get("extra_ota_keys")
973 if extra_ota_keys_info:
974 extra_ota_keys = [OPTIONS.key_map.get(k, k) + ".x509.pem"
975 for k in extra_ota_keys_info.split()]
976 print("extra ota key(s): " + ", ".join(extra_ota_keys))
977 else:
978 extra_ota_keys = []
979 for k in extra_ota_keys:
980 if not os.path.isfile(k):
981 raise common.ExternalError(k + " does not exist or is not a file")
982
983 extra_recovery_keys_info = misc_info.get("extra_recovery_keys")
984 if extra_recovery_keys_info:
Doug Zongkere121d6a2011-02-01 14:13:52 -0800985 extra_recovery_keys = [OPTIONS.key_map.get(k, k) + ".x509.pem"
Jacky Liubeb0b692021-12-29 16:29:05 +0800986 for k in extra_recovery_keys_info.split()]
987 print("extra recovery-only key(s): " + ", ".join(extra_recovery_keys))
Doug Zongkere121d6a2011-02-01 14:13:52 -0800988 else:
989 extra_recovery_keys = []
Jacky Liubeb0b692021-12-29 16:29:05 +0800990 for k in extra_recovery_keys:
991 if not os.path.isfile(k):
992 raise common.ExternalError(k + " does not exist or is not a file")
Doug Zongkere121d6a2011-02-01 14:13:52 -0800993
Doug Zongker8e931bf2009-04-06 15:21:45 -0700994 mapped_keys = []
995 for k in keylist:
996 m = re.match(r"^(.*)\.x509\.pem$", k)
997 if not m:
Doug Zongker412c02f2014-02-13 10:58:24 -0800998 raise common.ExternalError(
999 "can't parse \"%s\" from META/otakeys.txt" % (k,))
Doug Zongker8e931bf2009-04-06 15:21:45 -07001000 k = m.group(1)
1001 mapped_keys.append(OPTIONS.key_map.get(k, k) + ".x509.pem")
1002
Doug Zongkere05628c2009-08-20 17:38:42 -07001003 if mapped_keys:
Tao Bao0c28d2d2017-12-24 10:37:38 -08001004 print("using:\n ", "\n ".join(mapped_keys))
1005 print("for OTA package verification")
Doug Zongkere05628c2009-08-20 17:38:42 -07001006 else:
Doug Zongker831840e2011-09-22 10:28:04 -07001007 devkey = misc_info.get("default_system_dev_certificate",
Dan Willemsen0ab1be62019-04-09 21:35:37 -07001008 "build/make/target/product/security/testkey")
Tao Baof718f902017-11-09 10:10:10 -08001009 mapped_devkey = OPTIONS.key_map.get(devkey, devkey)
1010 if mapped_devkey != devkey:
1011 misc_info["default_system_dev_certificate"] = mapped_devkey
1012 mapped_keys.append(mapped_devkey + ".x509.pem")
Tao Baoa80ed222016-06-16 14:41:24 -07001013 print("META/otakeys.txt has no keys; using %s for OTA package"
1014 " verification." % (mapped_keys[0],))
Jacky Liubeb0b692021-12-29 16:29:05 +08001015 for k in mapped_keys:
1016 if not os.path.isfile(k):
1017 raise common.ExternalError(k + " does not exist or is not a file")
Doug Zongker8e931bf2009-04-06 15:21:45 -07001018
Kelvin Zhang9f781ff2021-02-11 19:10:44 -05001019 otacerts = [info
1020 for info in input_tf_zip.infolist()
1021 if info.filename.endswith("/otacerts.zip")]
1022 for info in otacerts:
Jacky Liubeb0b692021-12-29 16:29:05 +08001023 if info.filename.startswith(("BOOT/", "RECOVERY/", "VENDOR_BOOT/")):
1024 extra_keys = extra_recovery_keys
1025 else:
1026 extra_keys = extra_ota_keys
1027 print("Rewriting OTA key:", info.filename, mapped_keys + extra_keys)
1028 WriteOtacerts(output_tf_zip, info.filename, mapped_keys + extra_keys)
Doug Zongkereef39442009-04-02 12:14:19 -07001029
Tao Baoa80ed222016-06-16 14:41:24 -07001030
Tao Bao0c28d2d2017-12-24 10:37:38 -08001031def ReplaceVerityPublicKey(output_zip, filename, key_path):
1032 """Replaces the verity public key at the given path in the given zip.
1033
1034 Args:
1035 output_zip: The output target_files zip.
1036 filename: The archive name in the output zip.
1037 key_path: The path to the public key.
1038 """
1039 print("Replacing verity public key with %s" % (key_path,))
1040 common.ZipWrite(output_zip, key_path, arcname=filename)
Geremy Condraf19b3652014-07-29 17:54:54 -07001041
Tao Bao8adcfd12016-06-17 17:01:22 -07001042
Tao Bao46a59992017-06-05 11:55:16 -07001043def ReplaceVerityPrivateKey(misc_info, key_path):
Tao Bao0c28d2d2017-12-24 10:37:38 -08001044 """Replaces the verity private key in misc_info dict.
1045
1046 Args:
1047 misc_info: The info dict.
1048 key_path: The path to the private key in PKCS#8 format.
1049 """
1050 print("Replacing verity private key with %s" % (key_path,))
Andrew Boied083f0b2014-09-15 16:01:07 -07001051 misc_info["verity_key"] = key_path
Doug Zongkereef39442009-04-02 12:14:19 -07001052
Tao Bao8adcfd12016-06-17 17:01:22 -07001053
Tao Baoe838d142017-12-23 23:44:48 -08001054def ReplaceVerityKeyId(input_zip, output_zip, key_path):
1055 """Replaces the veritykeyid parameter in BOOT/cmdline.
1056
1057 Args:
1058 input_zip: The input target_files zip, which should be already open.
1059 output_zip: The output target_files zip, which should be already open and
1060 writable.
1061 key_path: The path to the PEM encoded X.509 certificate.
1062 """
Tao Baoa3705452019-06-24 15:33:41 -07001063 in_cmdline = input_zip.read("BOOT/cmdline").decode()
Tao Baoe838d142017-12-23 23:44:48 -08001064 # Copy in_cmdline to output_zip if veritykeyid is not present.
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001065 if "veritykeyid" not in in_cmdline:
Tao Baoe838d142017-12-23 23:44:48 -08001066 common.ZipWriteStr(output_zip, "BOOT/cmdline", in_cmdline)
1067 return
1068
Tao Bao0c28d2d2017-12-24 10:37:38 -08001069 out_buffer = []
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001070 for param in in_cmdline.split():
Tao Baoe838d142017-12-23 23:44:48 -08001071 if "veritykeyid" not in param:
Tao Bao0c28d2d2017-12-24 10:37:38 -08001072 out_buffer.append(param)
Tao Baoe838d142017-12-23 23:44:48 -08001073 continue
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001074
Tao Baoe838d142017-12-23 23:44:48 -08001075 # Extract keyid using openssl command.
1076 p = common.Run(["openssl", "x509", "-in", key_path, "-text"],
Tao Baode1d4792018-02-20 10:05:46 -08001077 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
Tao Baoe838d142017-12-23 23:44:48 -08001078 keyid, stderr = p.communicate()
1079 assert p.returncode == 0, "Failed to dump certificate: {}".format(stderr)
1080 keyid = re.search(
1081 r'keyid:([0-9a-fA-F:]*)', keyid).group(1).replace(':', '').lower()
1082 print("Replacing verity keyid with {}".format(keyid))
1083 out_buffer.append("veritykeyid=id:%s" % (keyid,))
1084
1085 out_cmdline = ' '.join(out_buffer).strip() + '\n'
1086 common.ZipWriteStr(output_zip, "BOOT/cmdline", out_cmdline)
Tao Bao46a59992017-06-05 11:55:16 -07001087
1088
1089def ReplaceMiscInfoTxt(input_zip, output_zip, misc_info):
1090 """Replaces META/misc_info.txt.
1091
1092 Only writes back the ones in the original META/misc_info.txt. Because the
1093 current in-memory dict contains additional items computed at runtime.
1094 """
1095 misc_info_old = common.LoadDictionaryFromLines(
Tao Baoa3705452019-06-24 15:33:41 -07001096 input_zip.read('META/misc_info.txt').decode().split('\n'))
Tao Bao46a59992017-06-05 11:55:16 -07001097 items = []
1098 for key in sorted(misc_info):
1099 if key in misc_info_old:
1100 items.append('%s=%s' % (key, misc_info[key]))
1101 common.ZipWriteStr(output_zip, "META/misc_info.txt", '\n'.join(items))
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001102
Tao Bao8adcfd12016-06-17 17:01:22 -07001103
Tao Bao639118f2017-06-19 15:48:02 -07001104def ReplaceAvbSigningKeys(misc_info):
1105 """Replaces the AVB signing keys."""
1106
Tao Bao639118f2017-06-19 15:48:02 -07001107 def ReplaceAvbPartitionSigningKey(partition):
1108 key = OPTIONS.avb_keys.get(partition)
1109 if not key:
1110 return
1111
1112 algorithm = OPTIONS.avb_algorithms.get(partition)
1113 assert algorithm, 'Missing AVB signing algorithm for %s' % (partition,)
1114
Tao Bao0c28d2d2017-12-24 10:37:38 -08001115 print('Replacing AVB signing key for %s with "%s" (%s)' % (
1116 partition, key, algorithm))
Tao Bao639118f2017-06-19 15:48:02 -07001117 misc_info['avb_' + partition + '_algorithm'] = algorithm
1118 misc_info['avb_' + partition + '_key_path'] = key
1119
1120 extra_args = OPTIONS.avb_extra_args.get(partition)
1121 if extra_args:
Tao Bao0c28d2d2017-12-24 10:37:38 -08001122 print('Setting extra AVB signing args for %s to "%s"' % (
1123 partition, extra_args))
Kelvin Zhang0876c412020-06-23 15:06:58 -04001124 args_key = AVB_FOOTER_ARGS_BY_PARTITION.get(
1125 partition,
1126 # custom partition
1127 "avb_{}_add_hashtree_footer_args".format(partition))
Tao Bao639118f2017-06-19 15:48:02 -07001128 misc_info[args_key] = (misc_info.get(args_key, '') + ' ' + extra_args)
1129
1130 for partition in AVB_FOOTER_ARGS_BY_PARTITION:
1131 ReplaceAvbPartitionSigningKey(partition)
1132
Hongguang Chenf23364d2020-04-27 18:36:36 -07001133 for custom_partition in misc_info.get(
Kelvin Zhang7cab7502021-08-02 19:58:14 -04001134 "avb_custom_images_partition_list", "").strip().split():
Hongguang Chenf23364d2020-04-27 18:36:36 -07001135 ReplaceAvbPartitionSigningKey(custom_partition)
1136
Tao Bao639118f2017-06-19 15:48:02 -07001137
Tao Bao19b02fe2019-10-09 00:04:28 -07001138def RewriteAvbProps(misc_info):
1139 """Rewrites the props in AVB signing args."""
1140 for partition, args_key in AVB_FOOTER_ARGS_BY_PARTITION.items():
1141 args = misc_info.get(args_key)
1142 if not args:
1143 continue
1144
1145 tokens = []
1146 changed = False
1147 for token in args.split(' '):
1148 fingerprint_key = 'com.android.build.{}.fingerprint'.format(partition)
1149 if not token.startswith(fingerprint_key):
1150 tokens.append(token)
1151 continue
1152 prefix, tag = token.rsplit('/', 1)
1153 tokens.append('{}/{}'.format(prefix, EditTags(tag)))
1154 changed = True
1155
1156 if changed:
1157 result = ' '.join(tokens)
1158 print('Rewriting AVB prop for {}:\n'.format(partition))
1159 print(' replace: {}'.format(args))
1160 print(' with: {}'.format(result))
1161 misc_info[args_key] = result
1162
1163
Bowgo Tsai27c39b02021-03-12 21:40:32 +08001164def ReplaceGkiSigningKey(misc_info):
1165 """Replaces the GKI signing key."""
1166
1167 key = OPTIONS.gki_signing_key
1168 if not key:
1169 return
1170
1171 algorithm = OPTIONS.gki_signing_algorithm
1172 if not algorithm:
1173 raise ValueError("Missing --gki_signing_algorithm")
1174
1175 print('Replacing GKI signing key with "%s" (%s)' % (key, algorithm))
1176 misc_info["gki_signing_algorithm"] = algorithm
1177 misc_info["gki_signing_key_path"] = key
1178
1179 extra_args = OPTIONS.gki_signing_extra_args
1180 if extra_args:
Bowgo Tsaibcae74d2021-05-10 17:35:37 +08001181 print('Setting GKI signing args: "%s"' % (extra_args))
1182 misc_info["gki_signing_signature_args"] = extra_args
Bowgo Tsai27c39b02021-03-12 21:40:32 +08001183
1184
Doug Zongker831840e2011-09-22 10:28:04 -07001185def BuildKeyMap(misc_info, key_mapping_options):
1186 for s, d in key_mapping_options:
1187 if s is None: # -d option
1188 devkey = misc_info.get("default_system_dev_certificate",
Dan Willemsen0ab1be62019-04-09 21:35:37 -07001189 "build/make/target/product/security/testkey")
Doug Zongker831840e2011-09-22 10:28:04 -07001190 devkeydir = os.path.dirname(devkey)
1191
1192 OPTIONS.key_map.update({
1193 devkeydir + "/testkey": d + "/releasekey",
1194 devkeydir + "/devkey": d + "/releasekey",
1195 devkeydir + "/media": d + "/media",
1196 devkeydir + "/shared": d + "/shared",
1197 devkeydir + "/platform": d + "/platform",
Oleh Cherpak982e6082019-12-10 12:58:54 +02001198 devkeydir + "/networkstack": d + "/networkstack",
Kelvin Zhang7cab7502021-08-02 19:58:14 -04001199 })
Doug Zongker831840e2011-09-22 10:28:04 -07001200 else:
1201 OPTIONS.key_map[s] = d
1202
1203
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001204def GetApiLevelAndCodename(input_tf_zip):
Tao Baoa3705452019-06-24 15:33:41 -07001205 data = input_tf_zip.read("SYSTEM/build.prop").decode()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001206 api_level = None
1207 codename = None
1208 for line in data.split("\n"):
1209 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001210 if line and line[0] != '#' and "=" in line:
1211 key, value = line.split("=", 1)
1212 key = key.strip()
1213 if key == "ro.build.version.sdk":
1214 api_level = int(value.strip())
1215 elif key == "ro.build.version.codename":
1216 codename = value.strip()
1217
1218 if api_level is None:
1219 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
1220 if codename is None:
1221 raise ValueError("No ro.build.version.codename in SYSTEM/build.prop")
1222
1223 return (api_level, codename)
1224
1225
1226def GetCodenameToApiLevelMap(input_tf_zip):
Tao Baoa3705452019-06-24 15:33:41 -07001227 data = input_tf_zip.read("SYSTEM/build.prop").decode()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001228 api_level = None
1229 codenames = None
1230 for line in data.split("\n"):
1231 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001232 if line and line[0] != '#' and "=" in line:
1233 key, value = line.split("=", 1)
1234 key = key.strip()
1235 if key == "ro.build.version.sdk":
1236 api_level = int(value.strip())
1237 elif key == "ro.build.version.all_codenames":
1238 codenames = value.strip().split(",")
1239
1240 if api_level is None:
1241 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
1242 if codenames is None:
1243 raise ValueError("No ro.build.version.all_codenames in SYSTEM/build.prop")
1244
Tao Baoa3705452019-06-24 15:33:41 -07001245 result = {}
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001246 for codename in codenames:
1247 codename = codename.strip()
Tao Baobadceb22019-03-15 09:33:43 -07001248 if codename:
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001249 result[codename] = api_level
1250 return result
1251
1252
Tao Baoaa7e9932019-03-15 09:37:01 -07001253def ReadApexKeysInfo(tf_zip):
1254 """Parses the APEX keys info from a given target-files zip.
1255
Melisa Carranza Zunigae6d4fb52022-03-07 14:56:26 +01001256 Given a target-files ZipFile, parses the META/apexkeys.txt entry and returns
1257 two dicts, the first one contains the mapping from APEX names
1258 (e.g. com.android.tzdata) to a tuple of (payload_key, container_key,
1259 sign_tool). The second one maps the sepolicy APEX name to a tuple containing
1260 (sepolicy_key, sepolicy_cert, fsverity_tool).
Tao Baoaa7e9932019-03-15 09:37:01 -07001261
1262 Args:
1263 tf_zip: The input target_files ZipFile (already open).
1264
1265 Returns:
Melisa Carranza Zunigae6d4fb52022-03-07 14:56:26 +01001266 name : (payload_key, container_key, sign_tool)
Jooyung Han8caba5e2021-10-27 03:58:09 +09001267 - payload_key contains the path to the payload signing key
1268 - container_key contains the path to the container signing key
1269 - sign_tool is an apex-specific signing tool for its payload contents
Melisa Carranza Zunigae6d4fb52022-03-07 14:56:26 +01001270 name : (sepolicy_key, sepolicy_cert, fsverity_tool)
Tao Baoaa7e9932019-03-15 09:37:01 -07001271 """
1272 keys = {}
Melisa Carranza Zunigae6d4fb52022-03-07 14:56:26 +01001273 sepolicy_keys = {}
Tao Baoa3705452019-06-24 15:33:41 -07001274 for line in tf_zip.read('META/apexkeys.txt').decode().split('\n'):
Tao Baoaa7e9932019-03-15 09:37:01 -07001275 line = line.strip()
1276 if not line:
1277 continue
1278 matches = re.match(
1279 r'^name="(?P<NAME>.*)"\s+'
1280 r'public_key="(?P<PAYLOAD_PUBLIC_KEY>.*)"\s+'
1281 r'private_key="(?P<PAYLOAD_PRIVATE_KEY>.*)"\s+'
1282 r'container_certificate="(?P<CONTAINER_CERT>.*)"\s+'
Bill Peckham5c7b0342020-04-03 15:36:23 -07001283 r'container_private_key="(?P<CONTAINER_PRIVATE_KEY>.*?)"'
Melisa Carranza Zunigae6d4fb52022-03-07 14:56:26 +01001284 r'(\s+sepolicy_key="(?P<SEPOLICY_KEY>.*?)")?'
1285 r'(\s+sepolicy_certificate="(?P<SEPOLICY_CERT>.*?)")?'
1286 r'(\s+fsverity_tool="(?P<FSVERITY_TOOL>.*?)")?'
Jooyung Han8caba5e2021-10-27 03:58:09 +09001287 r'(\s+partition="(?P<PARTITION>.*?)")?'
1288 r'(\s+sign_tool="(?P<SIGN_TOOL>.*?)")?$',
Tao Baoaa7e9932019-03-15 09:37:01 -07001289 line)
1290 if not matches:
1291 continue
1292
1293 name = matches.group('NAME')
Tao Baoaa7e9932019-03-15 09:37:01 -07001294 payload_private_key = matches.group("PAYLOAD_PRIVATE_KEY")
1295
1296 def CompareKeys(pubkey, pubkey_suffix, privkey, privkey_suffix):
1297 pubkey_suffix_len = len(pubkey_suffix)
1298 privkey_suffix_len = len(privkey_suffix)
1299 return (pubkey.endswith(pubkey_suffix) and
1300 privkey.endswith(privkey_suffix) and
1301 pubkey[:-pubkey_suffix_len] == privkey[:-privkey_suffix_len])
1302
Ivan Lozanob021b2a2020-07-28 09:31:06 -04001303 # Check the container key names, as we'll carry them without the
Tao Bao6d9e3da2019-03-26 12:59:25 -07001304 # extensions. This doesn't apply to payload keys though, which we will use
1305 # full names only.
Tao Baoaa7e9932019-03-15 09:37:01 -07001306 container_cert = matches.group("CONTAINER_CERT")
1307 container_private_key = matches.group("CONTAINER_PRIVATE_KEY")
Tao Baof454c3a2019-04-24 23:53:42 -07001308 if container_cert == 'PRESIGNED' and container_private_key == 'PRESIGNED':
1309 container_key = 'PRESIGNED'
1310 elif CompareKeys(
Kelvin Zhang7cab7502021-08-02 19:58:14 -04001311 container_cert, OPTIONS.public_key_suffix,
1312 container_private_key, OPTIONS.private_key_suffix):
Tao Baof454c3a2019-04-24 23:53:42 -07001313 container_key = container_cert[:-len(OPTIONS.public_key_suffix)]
1314 else:
Melisa Carranza Zunigae6d4fb52022-03-07 14:56:26 +01001315 raise ValueError("Failed to parse container keys: \n{} **** {}".format(container_cert, container_private_key))
Tao Baoaa7e9932019-03-15 09:37:01 -07001316
Jooyung Han8caba5e2021-10-27 03:58:09 +09001317 sign_tool = matches.group("SIGN_TOOL")
1318 keys[name] = (payload_private_key, container_key, sign_tool)
Tao Baoaa7e9932019-03-15 09:37:01 -07001319
Melisa Carranza Zunigae6d4fb52022-03-07 14:56:26 +01001320 if IsSepolicyApex(name):
1321 sepolicy_key = matches.group('SEPOLICY_KEY')
1322 sepolicy_cert = matches.group('SEPOLICY_CERT')
1323 fsverity_tool = matches.group('FSVERITY_TOOL')
1324 sepolicy_keys[name] = (sepolicy_key, sepolicy_cert, fsverity_tool)
1325
1326 return keys, sepolicy_keys
Tao Baoaa7e9932019-03-15 09:37:01 -07001327
1328
Daniel Norman78554ea2021-09-14 10:29:38 -07001329def BuildVendorPartitions(output_zip_path):
1330 """Builds OPTIONS.vendor_partitions using OPTIONS.vendor_otatools."""
1331 if OPTIONS.vendor_partitions.difference(ALLOWED_VENDOR_PARTITIONS):
1332 logger.warning("Allowed --vendor_partitions: %s",
1333 ",".join(ALLOWED_VENDOR_PARTITIONS))
1334 OPTIONS.vendor_partitions = ALLOWED_VENDOR_PARTITIONS.intersection(
1335 OPTIONS.vendor_partitions)
1336
1337 logger.info("Building vendor partitions using vendor otatools.")
1338 vendor_tempdir = common.UnzipTemp(output_zip_path, [
1339 "META/*",
Po Hu0663ae42021-09-27 12:59:06 +08001340 "SYSTEM/build.prop",
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001341 "RECOVERY/*",
1342 "BOOT/*",
1343 "OTA/",
Daniel Norman78554ea2021-09-14 10:29:38 -07001344 ] + ["{}/*".format(p.upper()) for p in OPTIONS.vendor_partitions])
1345
1346 # Disable various partitions that build based on misc_info fields.
1347 # Only partitions in ALLOWED_VENDOR_PARTITIONS can be rebuilt using
1348 # vendor otatools. These other partitions will be rebuilt using the main
1349 # otatools if necessary.
1350 vendor_misc_info_path = os.path.join(vendor_tempdir, "META/misc_info.txt")
1351 vendor_misc_info = common.LoadDictionaryFromFile(vendor_misc_info_path)
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001352 # Ignore if not rebuilding recovery
1353 if not OPTIONS.rebuild_recovery:
1354 vendor_misc_info["no_boot"] = "true" # boot
1355 vendor_misc_info["vendor_boot"] = "false" # vendor_boot
1356 vendor_misc_info["no_recovery"] = "true" # recovery
Iavor-Valentin Iftime40adb172022-04-19 18:17:56 +00001357 vendor_misc_info["avb_enable"] = "false" # vbmeta
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001358
Daniel Norman78554ea2021-09-14 10:29:38 -07001359 vendor_misc_info["board_bpt_enable"] = "false" # partition-table
1360 vendor_misc_info["has_dtbo"] = "false" # dtbo
1361 vendor_misc_info["has_pvmfw"] = "false" # pvmfw
1362 vendor_misc_info["avb_custom_images_partition_list"] = "" # custom images
Iavor-Valentin Iftime40adb172022-04-19 18:17:56 +00001363 vendor_misc_info["avb_building_vbmeta_image"] = "false" # skip building vbmeta
Daniel Norman78554ea2021-09-14 10:29:38 -07001364 vendor_misc_info["use_dynamic_partitions"] = "false" # super_empty
1365 vendor_misc_info["build_super_partition"] = "false" # super split
1366 with open(vendor_misc_info_path, "w") as output:
1367 for key in sorted(vendor_misc_info):
1368 output.write("{}={}\n".format(key, vendor_misc_info[key]))
1369
Po Hu0663ae42021-09-27 12:59:06 +08001370 # Disable system partition by a placeholder of IMAGES/system.img,
1371 # instead of removing SYSTEM folder.
1372 # Because SYSTEM/build.prop is still needed for:
1373 # add_img_to_target_files.CreateImage ->
1374 # common.BuildInfo ->
1375 # common.BuildInfo.CalculateFingerprint
1376 vendor_images_path = os.path.join(vendor_tempdir, "IMAGES")
1377 if not os.path.exists(vendor_images_path):
1378 os.makedirs(vendor_images_path)
1379 with open(os.path.join(vendor_images_path, "system.img"), "w") as output:
1380 pass
1381
Daniel Norman78554ea2021-09-14 10:29:38 -07001382 # Disable care_map.pb as not all ab_partitions are available when
1383 # vendor otatools regenerates vendor images.
Po Hu0663ae42021-09-27 12:59:06 +08001384 if os.path.exists(os.path.join(vendor_tempdir, "META/ab_partitions.txt")):
1385 os.remove(os.path.join(vendor_tempdir, "META/ab_partitions.txt"))
1386 # Disable RADIO images
1387 if os.path.exists(os.path.join(vendor_tempdir, "META/pack_radioimages.txt")):
1388 os.remove(os.path.join(vendor_tempdir, "META/pack_radioimages.txt"))
Daniel Norman78554ea2021-09-14 10:29:38 -07001389
1390 # Build vendor images using vendor otatools.
Iavor-Valentin Iftime63cde0f2022-03-04 16:02:44 +00001391 # Accept either a zip file or extracted directory.
1392 if os.path.isfile(OPTIONS.vendor_otatools):
1393 vendor_otatools_dir = common.MakeTempDir(prefix="vendor_otatools_")
1394 common.UnzipToDir(OPTIONS.vendor_otatools, vendor_otatools_dir)
1395 else:
1396 vendor_otatools_dir = OPTIONS.vendor_otatools
Daniel Norman78554ea2021-09-14 10:29:38 -07001397 cmd = [
1398 os.path.join(vendor_otatools_dir, "bin", "add_img_to_target_files"),
1399 "--is_signing",
Po Hu0663ae42021-09-27 12:59:06 +08001400 "--add_missing",
Daniel Norman78554ea2021-09-14 10:29:38 -07001401 "--verbose",
1402 vendor_tempdir,
1403 ]
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001404 if OPTIONS.rebuild_recovery:
1405 cmd.insert(4, "--rebuild_recovery")
1406
Daniel Norman78554ea2021-09-14 10:29:38 -07001407 common.RunAndCheckOutput(cmd, verbose=True)
1408
1409 logger.info("Writing vendor partitions to output archive.")
1410 with zipfile.ZipFile(
1411 output_zip_path, "a", compression=zipfile.ZIP_DEFLATED,
1412 allowZip64=True) as output_zip:
1413 for p in OPTIONS.vendor_partitions:
Iavor-Valentin Iftime880e4432022-03-17 14:02:27 +00001414 img_file_path = "IMAGES/{}.img".format(p)
1415 map_file_path = "IMAGES/{}.map".format(p)
1416 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, img_file_path), img_file_path)
1417 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, map_file_path), map_file_path)
Iavor-Valentin Iftime40adb172022-04-19 18:17:56 +00001418 # copy recovery.img, boot.img, recovery patch & install.sh
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001419 if OPTIONS.rebuild_recovery:
Iavor-Valentin Iftime40adb172022-04-19 18:17:56 +00001420 recovery_img = "IMAGES/recovery.img"
1421 boot_img = "IMAGES/boot.img"
1422 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, recovery_img), recovery_img)
1423 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, boot_img), boot_img)
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001424 recovery_patch_path = "VENDOR/recovery-from-boot.p"
1425 recovery_sh_path = "VENDOR/bin/install-recovery.sh"
1426 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, recovery_patch_path), recovery_patch_path)
1427 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, recovery_sh_path), recovery_sh_path)
Daniel Norman78554ea2021-09-14 10:29:38 -07001428
1429
Doug Zongkereef39442009-04-02 12:14:19 -07001430def main(argv):
1431
Doug Zongker831840e2011-09-22 10:28:04 -07001432 key_mapping_options = []
1433
Doug Zongkereef39442009-04-02 12:14:19 -07001434 def option_handler(o, a):
Doug Zongker05d3dea2009-06-22 11:32:31 -07001435 if o in ("-e", "--extra_apks"):
Doug Zongkereef39442009-04-02 12:14:19 -07001436 names, key = a.split("=")
1437 names = names.split(",")
1438 for n in names:
1439 OPTIONS.extra_apks[n] = key
Tao Baoaa7e9932019-03-15 09:37:01 -07001440 elif o == "--extra_apex_payload_key":
1441 apex_name, key = a.split("=")
1442 OPTIONS.extra_apex_payload_keys[apex_name] = key
Tao Bao93c2a012018-06-19 12:19:35 -07001443 elif o == "--skip_apks_with_path_prefix":
Tianjiea85bdf02020-07-29 11:56:19 -07001444 # Check the prefix, which must be in all upper case.
Tao Bao93c2a012018-06-19 12:19:35 -07001445 prefix = a.split('/')[0]
1446 if not prefix or prefix != prefix.upper():
1447 raise ValueError("Invalid path prefix '%s'" % (a,))
1448 OPTIONS.skip_apks_with_path_prefix.add(a)
Doug Zongkereef39442009-04-02 12:14:19 -07001449 elif o in ("-d", "--default_key_mappings"):
Doug Zongker831840e2011-09-22 10:28:04 -07001450 key_mapping_options.append((None, a))
Doug Zongkereef39442009-04-02 12:14:19 -07001451 elif o in ("-k", "--key_mapping"):
Doug Zongker831840e2011-09-22 10:28:04 -07001452 key_mapping_options.append(a.split("=", 1))
Doug Zongker8e931bf2009-04-06 15:21:45 -07001453 elif o in ("-o", "--replace_ota_keys"):
1454 OPTIONS.replace_ota_keys = True
Doug Zongkerae877012009-04-21 10:04:51 -07001455 elif o in ("-t", "--tag_changes"):
1456 new = []
1457 for i in a.split(","):
1458 i = i.strip()
1459 if not i or i[0] not in "-+":
1460 raise ValueError("Bad tag change '%s'" % (i,))
1461 new.append(i[0] + i[1:].strip())
1462 OPTIONS.tag_changes = tuple(new)
Geremy Condraf19b3652014-07-29 17:54:54 -07001463 elif o == "--replace_verity_public_key":
1464 OPTIONS.replace_verity_public_key = (True, a)
1465 elif o == "--replace_verity_private_key":
1466 OPTIONS.replace_verity_private_key = (True, a)
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001467 elif o == "--replace_verity_keyid":
1468 OPTIONS.replace_verity_keyid = (True, a)
Bowgo Tsai2fe786a2020-02-21 17:48:18 +08001469 elif o == "--remove_avb_public_keys":
1470 OPTIONS.remove_avb_public_keys = a.split(",")
Tao Bao639118f2017-06-19 15:48:02 -07001471 elif o == "--avb_vbmeta_key":
1472 OPTIONS.avb_keys['vbmeta'] = a
1473 elif o == "--avb_vbmeta_algorithm":
1474 OPTIONS.avb_algorithms['vbmeta'] = a
1475 elif o == "--avb_vbmeta_extra_args":
1476 OPTIONS.avb_extra_args['vbmeta'] = a
1477 elif o == "--avb_boot_key":
1478 OPTIONS.avb_keys['boot'] = a
1479 elif o == "--avb_boot_algorithm":
1480 OPTIONS.avb_algorithms['boot'] = a
1481 elif o == "--avb_boot_extra_args":
1482 OPTIONS.avb_extra_args['boot'] = a
1483 elif o == "--avb_dtbo_key":
1484 OPTIONS.avb_keys['dtbo'] = a
1485 elif o == "--avb_dtbo_algorithm":
1486 OPTIONS.avb_algorithms['dtbo'] = a
1487 elif o == "--avb_dtbo_extra_args":
1488 OPTIONS.avb_extra_args['dtbo'] = a
1489 elif o == "--avb_system_key":
1490 OPTIONS.avb_keys['system'] = a
1491 elif o == "--avb_system_algorithm":
1492 OPTIONS.avb_algorithms['system'] = a
1493 elif o == "--avb_system_extra_args":
1494 OPTIONS.avb_extra_args['system'] = a
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001495 elif o == "--avb_system_other_key":
1496 OPTIONS.avb_keys['system_other'] = a
1497 elif o == "--avb_system_other_algorithm":
1498 OPTIONS.avb_algorithms['system_other'] = a
1499 elif o == "--avb_system_other_extra_args":
1500 OPTIONS.avb_extra_args['system_other'] = a
Tao Bao639118f2017-06-19 15:48:02 -07001501 elif o == "--avb_vendor_key":
1502 OPTIONS.avb_keys['vendor'] = a
1503 elif o == "--avb_vendor_algorithm":
1504 OPTIONS.avb_algorithms['vendor'] = a
1505 elif o == "--avb_vendor_extra_args":
1506 OPTIONS.avb_extra_args['vendor'] = a
Tao Baod6085d62019-05-06 12:55:42 -07001507 elif o == "--avb_vbmeta_system_key":
1508 OPTIONS.avb_keys['vbmeta_system'] = a
1509 elif o == "--avb_vbmeta_system_algorithm":
1510 OPTIONS.avb_algorithms['vbmeta_system'] = a
1511 elif o == "--avb_vbmeta_system_extra_args":
1512 OPTIONS.avb_extra_args['vbmeta_system'] = a
1513 elif o == "--avb_vbmeta_vendor_key":
1514 OPTIONS.avb_keys['vbmeta_vendor'] = a
1515 elif o == "--avb_vbmeta_vendor_algorithm":
1516 OPTIONS.avb_algorithms['vbmeta_vendor'] = a
1517 elif o == "--avb_vbmeta_vendor_extra_args":
1518 OPTIONS.avb_extra_args['vbmeta_vendor'] = a
Tao Baoaa7e9932019-03-15 09:37:01 -07001519 elif o == "--avb_apex_extra_args":
1520 OPTIONS.avb_extra_args['apex'] = a
Hongguang Chenf23364d2020-04-27 18:36:36 -07001521 elif o == "--avb_extra_custom_image_key":
1522 partition, key = a.split("=")
1523 OPTIONS.avb_keys[partition] = key
1524 elif o == "--avb_extra_custom_image_algorithm":
1525 partition, algorithm = a.split("=")
1526 OPTIONS.avb_algorithms[partition] = algorithm
1527 elif o == "--avb_extra_custom_image_extra_args":
Hongguang Chen883eecb2020-05-23 22:20:19 -07001528 # Setting the maxsplit parameter to one, which will return a list with
1529 # two elements. e.g., the second '=' should not be splitted for
1530 # 'oem=--signing_helper_with_files=/tmp/avbsigner.sh'.
1531 partition, extra_args = a.split("=", 1)
Hongguang Chenf23364d2020-04-27 18:36:36 -07001532 OPTIONS.avb_extra_args[partition] = extra_args
Bowgo Tsai27c39b02021-03-12 21:40:32 +08001533 elif o == "--gki_signing_key":
1534 OPTIONS.gki_signing_key = a
1535 elif o == "--gki_signing_algorithm":
1536 OPTIONS.gki_signing_algorithm = a
1537 elif o == "--gki_signing_extra_args":
1538 OPTIONS.gki_signing_extra_args = a
Daniel Norman78554ea2021-09-14 10:29:38 -07001539 elif o == "--vendor_otatools":
1540 OPTIONS.vendor_otatools = a
1541 elif o == "--vendor_partitions":
1542 OPTIONS.vendor_partitions = set(a.split(","))
Melisa Carranza Zunigae6d4fb52022-03-07 14:56:26 +01001543 elif o == '--sepolicy_key':
1544 OPTIONS.sepolicy_key = a
1545 elif o == '--sepolicy_cert':
1546 OPTIONS.sepolicy_cert = a
1547 elif o == '--fsverity_tool':
1548 OPTIONS.fsverity_tool = a
Bowgo Tsai2a781692021-10-13 17:39:33 +08001549 elif o == "--allow_gsi_debug_sepolicy":
1550 OPTIONS.allow_gsi_debug_sepolicy = True
Doug Zongkereef39442009-04-02 12:14:19 -07001551 else:
1552 return False
1553 return True
1554
Tao Bao639118f2017-06-19 15:48:02 -07001555 args = common.ParseOptions(
1556 argv, __doc__,
1557 extra_opts="e:d:k:ot:",
1558 extra_long_opts=[
Tao Bao0c28d2d2017-12-24 10:37:38 -08001559 "extra_apks=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001560 "extra_apex_payload_key=",
Tao Bao93c2a012018-06-19 12:19:35 -07001561 "skip_apks_with_path_prefix=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001562 "default_key_mappings=",
1563 "key_mapping=",
1564 "replace_ota_keys",
1565 "tag_changes=",
1566 "replace_verity_public_key=",
1567 "replace_verity_private_key=",
1568 "replace_verity_keyid=",
Bowgo Tsai2fe786a2020-02-21 17:48:18 +08001569 "remove_avb_public_keys=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001570 "avb_apex_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001571 "avb_vbmeta_algorithm=",
1572 "avb_vbmeta_key=",
1573 "avb_vbmeta_extra_args=",
1574 "avb_boot_algorithm=",
1575 "avb_boot_key=",
1576 "avb_boot_extra_args=",
1577 "avb_dtbo_algorithm=",
1578 "avb_dtbo_key=",
1579 "avb_dtbo_extra_args=",
1580 "avb_system_algorithm=",
1581 "avb_system_key=",
1582 "avb_system_extra_args=",
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001583 "avb_system_other_algorithm=",
1584 "avb_system_other_key=",
1585 "avb_system_other_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001586 "avb_vendor_algorithm=",
1587 "avb_vendor_key=",
1588 "avb_vendor_extra_args=",
Tao Baod6085d62019-05-06 12:55:42 -07001589 "avb_vbmeta_system_algorithm=",
1590 "avb_vbmeta_system_key=",
1591 "avb_vbmeta_system_extra_args=",
1592 "avb_vbmeta_vendor_algorithm=",
1593 "avb_vbmeta_vendor_key=",
1594 "avb_vbmeta_vendor_extra_args=",
Hongguang Chenf23364d2020-04-27 18:36:36 -07001595 "avb_extra_custom_image_key=",
1596 "avb_extra_custom_image_algorithm=",
1597 "avb_extra_custom_image_extra_args=",
Bowgo Tsai27c39b02021-03-12 21:40:32 +08001598 "gki_signing_key=",
1599 "gki_signing_algorithm=",
1600 "gki_signing_extra_args=",
Daniel Norman78554ea2021-09-14 10:29:38 -07001601 "vendor_partitions=",
1602 "vendor_otatools=",
Melisa Carranza Zunigae6d4fb52022-03-07 14:56:26 +01001603 "sepolicy_key=",
1604 "sepolicy_cert=",
1605 "fsverity_tool=",
Bowgo Tsai2a781692021-10-13 17:39:33 +08001606 "allow_gsi_debug_sepolicy",
Tao Bao639118f2017-06-19 15:48:02 -07001607 ],
1608 extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001609
1610 if len(args) != 2:
1611 common.Usage(__doc__)
1612 sys.exit(1)
1613
Tao Baobadceb22019-03-15 09:33:43 -07001614 common.InitLogging()
1615
Kelvin Zhang928c2342020-09-22 16:15:57 -04001616 input_zip = zipfile.ZipFile(args[0], "r", allowZip64=True)
Tao Bao2b8f4892017-06-13 12:54:58 -07001617 output_zip = zipfile.ZipFile(args[1], "w",
1618 compression=zipfile.ZIP_DEFLATED,
1619 allowZip64=True)
Doug Zongkereef39442009-04-02 12:14:19 -07001620
Doug Zongker831840e2011-09-22 10:28:04 -07001621 misc_info = common.LoadInfoDict(input_zip)
1622
1623 BuildKeyMap(misc_info, key_mapping_options)
1624
Tao Baoaa7e9932019-03-15 09:37:01 -07001625 apk_keys_info, compressed_extension = common.ReadApkCerts(input_zip)
1626 apk_keys = GetApkCerts(apk_keys_info)
Doug Zongkereb338ef2009-05-20 16:50:49 -07001627
Melisa Carranza Zunigae6d4fb52022-03-07 14:56:26 +01001628 apex_keys_info, sepolicy_keys_info = ReadApexKeysInfo(input_zip)
Tao Baoaa7e9932019-03-15 09:37:01 -07001629 apex_keys = GetApexKeys(apex_keys_info, apk_keys)
Melisa Carranza Zunigae6d4fb52022-03-07 14:56:26 +01001630 sepolicy_keys = GetSepolicyKeys(sepolicy_keys_info)
Tao Baoaa7e9932019-03-15 09:37:01 -07001631
Tianjie Xu88a759d2020-01-23 10:47:54 -08001632 # TODO(xunchang) check for the apks inside the apex files, and abort early if
1633 # the keys are not available.
Tao Baoaa7e9932019-03-15 09:37:01 -07001634 CheckApkAndApexKeysAvailable(
1635 input_zip,
1636 set(apk_keys.keys()) | set(apex_keys.keys()),
Tao Baoe1343992019-03-19 12:24:03 -07001637 compressed_extension,
1638 apex_keys)
Tao Baoaa7e9932019-03-15 09:37:01 -07001639
1640 key_passwords = common.GetKeyPasswords(
1641 set(apk_keys.values()) | set(itertools.chain(*apex_keys.values())))
Tao Bao9aa4b9b2016-09-29 17:53:56 -07001642 platform_api_level, _ = GetApiLevelAndCodename(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001643 codename_to_api_level_map = GetCodenameToApiLevelMap(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001644
Doug Zongker412c02f2014-02-13 10:58:24 -08001645 ProcessTargetFiles(input_zip, output_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -07001646 apk_keys, apex_keys, key_passwords,
1647 platform_api_level, codename_to_api_level_map,
Melisa Carranza Zunigae6d4fb52022-03-07 14:56:26 +01001648 compressed_extension, sepolicy_keys)
Doug Zongker8e931bf2009-04-06 15:21:45 -07001649
Tao Bao2ed665a2015-04-01 11:21:55 -07001650 common.ZipClose(input_zip)
1651 common.ZipClose(output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001652
Daniel Norman78554ea2021-09-14 10:29:38 -07001653 if OPTIONS.vendor_partitions and OPTIONS.vendor_otatools:
1654 BuildVendorPartitions(args[1])
1655
Tianjie Xub48589a2016-08-03 19:21:52 -07001656 # Skip building userdata.img and cache.img when signing the target files.
Daniel Norman78554ea2021-09-14 10:29:38 -07001657 new_args = ["--is_signing", "--add_missing", "--verbose"]
Tianjie Xu616fbeb2017-05-23 14:51:02 -07001658 # add_img_to_target_files builds the system image from scratch, so the
1659 # recovery patch is guaranteed to be regenerated there.
1660 if OPTIONS.rebuild_recovery:
1661 new_args.append("--rebuild_recovery")
1662 new_args.append(args[1])
Tianjie Xub48589a2016-08-03 19:21:52 -07001663 add_img_to_target_files.main(new_args)
Doug Zongker3c84f562014-07-31 11:06:30 -07001664
Tao Bao0c28d2d2017-12-24 10:37:38 -08001665 print("done.")
Doug Zongkereef39442009-04-02 12:14:19 -07001666
1667
1668if __name__ == '__main__':
1669 try:
1670 main(sys.argv[1:])
Tao Bao639118f2017-06-19 15:48:02 -07001671 finally:
1672 common.Cleanup()