blob: ae72430aa1ef96dc976daf2f0c08221dcbb32506 [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
Kelvin Zhang085b6f32022-07-25 16:12:30 -070030 --extra_apex_payload_key <name,name,...=key>
Tao Baoaa7e9932019-03-15 09:37:01 -070031 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
140 --allow_gsi_debug_sepolicy
141 Allow the existence of the file 'userdebug_plat_sepolicy.cil' under
142 (/system/system_ext|/system_ext)/etc/selinux.
143 If not set, error out when the file exists.
Kelvin Zhange50bb512022-08-01 15:58:51 -0700144
145 --override_apk_keys <path>
146 Replace all APK keys with this private key
147
148 --override_apex_keys <path>
149 Replace all APEX keys with this private key
Doug Zongkereef39442009-04-02 12:14:19 -0700150"""
151
Tao Bao0c28d2d2017-12-24 10:37:38 -0800152from __future__ import print_function
Doug Zongkereef39442009-04-02 12:14:19 -0700153
Robert Craig817c5742013-04-19 10:59:22 -0400154import base64
Doug Zongker8e931bf2009-04-06 15:21:45 -0700155import copy
Robert Craig817c5742013-04-19 10:59:22 -0400156import errno
Narayan Kamatha07bf042017-08-14 14:49:21 +0100157import gzip
Tao Baobb733882019-07-24 23:31:19 -0700158import io
Tao Baoaa7e9932019-03-15 09:37:01 -0700159import itertools
Tao Baobadceb22019-03-15 09:33:43 -0700160import logging
Doug Zongkereef39442009-04-02 12:14:19 -0700161import os
162import re
Narayan Kamatha07bf042017-08-14 14:49:21 +0100163import shutil
Tao Bao9fdd00f2017-07-12 11:57:05 -0700164import stat
Doug Zongkereef39442009-04-02 12:14:19 -0700165import subprocess
Tao Bao0c28d2d2017-12-24 10:37:38 -0800166import sys
Doug Zongkereef39442009-04-02 12:14:19 -0700167import tempfile
168import zipfile
Tao Bao66472632017-12-04 17:16:36 -0800169from xml.etree import ElementTree
Doug Zongkereef39442009-04-02 12:14:19 -0700170
Doug Zongker3c84f562014-07-31 11:06:30 -0700171import add_img_to_target_files
Tao Baoaa7e9932019-03-15 09:37:01 -0700172import apex_utils
Doug Zongkereef39442009-04-02 12:14:19 -0700173import common
174
Tao Bao0c28d2d2017-12-24 10:37:38 -0800175
176if sys.hexversion < 0x02070000:
177 print("Python 2.7 or newer is required.", file=sys.stderr)
178 sys.exit(1)
179
180
Tao Baobadceb22019-03-15 09:33:43 -0700181logger = logging.getLogger(__name__)
182
Doug Zongkereef39442009-04-02 12:14:19 -0700183OPTIONS = common.OPTIONS
184
185OPTIONS.extra_apks = {}
Tao Baoaa7e9932019-03-15 09:37:01 -0700186OPTIONS.extra_apex_payload_keys = {}
Tao Bao93c2a012018-06-19 12:19:35 -0700187OPTIONS.skip_apks_with_path_prefix = set()
Doug Zongkereef39442009-04-02 12:14:19 -0700188OPTIONS.key_map = {}
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700189OPTIONS.rebuild_recovery = False
Doug Zongker8e931bf2009-04-06 15:21:45 -0700190OPTIONS.replace_ota_keys = False
Geremy Condraf19b3652014-07-29 17:54:54 -0700191OPTIONS.replace_verity_public_key = False
192OPTIONS.replace_verity_private_key = False
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700193OPTIONS.replace_verity_keyid = False
Bowgo Tsai2fe786a2020-02-21 17:48:18 +0800194OPTIONS.remove_avb_public_keys = None
Doug Zongker831840e2011-09-22 10:28:04 -0700195OPTIONS.tag_changes = ("-test-keys", "-dev-keys", "+release-keys")
Tao Bao639118f2017-06-19 15:48:02 -0700196OPTIONS.avb_keys = {}
197OPTIONS.avb_algorithms = {}
198OPTIONS.avb_extra_args = {}
Bowgo Tsai27c39b02021-03-12 21:40:32 +0800199OPTIONS.gki_signing_key = None
200OPTIONS.gki_signing_algorithm = None
201OPTIONS.gki_signing_extra_args = None
Tianjie Xu88a759d2020-01-23 10:47:54 -0800202OPTIONS.android_jar_path = None
Daniel Norman78554ea2021-09-14 10:29:38 -0700203OPTIONS.vendor_partitions = set()
204OPTIONS.vendor_otatools = None
Bowgo Tsai2a781692021-10-13 17:39:33 +0800205OPTIONS.allow_gsi_debug_sepolicy = False
Kelvin Zhange50bb512022-08-01 15:58:51 -0700206OPTIONS.override_apk_keys = None
207OPTIONS.override_apex_keys = None
Doug Zongkereef39442009-04-02 12:14:19 -0700208
Tao Bao0c28d2d2017-12-24 10:37:38 -0800209
Tao Bao19b02fe2019-10-09 00:04:28 -0700210AVB_FOOTER_ARGS_BY_PARTITION = {
Tianjiebf0b8a82021-03-03 17:31:04 -0800211 'boot': 'avb_boot_add_hash_footer_args',
Devin Mooreafdd7c72021-12-13 22:04:08 +0000212 'init_boot': 'avb_init_boot_add_hash_footer_args',
Tianjiebf0b8a82021-03-03 17:31:04 -0800213 'dtbo': 'avb_dtbo_add_hash_footer_args',
214 'product': 'avb_product_add_hashtree_footer_args',
215 'recovery': 'avb_recovery_add_hash_footer_args',
216 'system': 'avb_system_add_hashtree_footer_args',
Ramji Jiyani13a41372022-01-27 07:05:08 +0000217 'system_dlkm': "avb_system_dlkm_add_hashtree_footer_args",
Tianjiebf0b8a82021-03-03 17:31:04 -0800218 'system_ext': 'avb_system_ext_add_hashtree_footer_args',
219 'system_other': 'avb_system_other_add_hashtree_footer_args',
220 'odm': 'avb_odm_add_hashtree_footer_args',
221 'odm_dlkm': 'avb_odm_dlkm_add_hashtree_footer_args',
222 'pvmfw': 'avb_pvmfw_add_hash_footer_args',
223 'vendor': 'avb_vendor_add_hashtree_footer_args',
224 'vendor_boot': 'avb_vendor_boot_add_hash_footer_args',
Lucas Wei03230252022-04-18 16:00:40 +0800225 'vendor_kernel_boot': 'avb_vendor_kernel_boot_add_hash_footer_args',
Tianjiebf0b8a82021-03-03 17:31:04 -0800226 'vendor_dlkm': "avb_vendor_dlkm_add_hashtree_footer_args",
227 'vbmeta': 'avb_vbmeta_args',
228 'vbmeta_system': 'avb_vbmeta_system_args',
229 'vbmeta_vendor': 'avb_vbmeta_vendor_args',
Tao Bao19b02fe2019-10-09 00:04:28 -0700230}
231
232
Tianjiebf0b8a82021-03-03 17:31:04 -0800233# Check that AVB_FOOTER_ARGS_BY_PARTITION is in sync with AVB_PARTITIONS.
234for partition in common.AVB_PARTITIONS:
235 if partition not in AVB_FOOTER_ARGS_BY_PARTITION:
236 raise RuntimeError("Missing {} in AVB_FOOTER_ARGS".format(partition))
237
Daniel Norman78554ea2021-09-14 10:29:38 -0700238# Partitions that can be regenerated after signing using a separate
239# vendor otatools package.
240ALLOWED_VENDOR_PARTITIONS = set(["vendor", "odm"])
241
Tianjiebf0b8a82021-03-03 17:31:04 -0800242
Tianjie4d48d502021-06-11 17:03:43 -0700243def IsApexFile(filename):
244 return filename.endswith(".apex") or filename.endswith(".capex")
245
246
247def GetApexFilename(filename):
248 name = os.path.basename(filename)
249 # Replace the suffix for compressed apex
250 if name.endswith(".capex"):
251 return name.replace(".capex", ".apex")
252 return name
253
254
Narayan Kamatha07bf042017-08-14 14:49:21 +0100255def GetApkCerts(certmap):
Kelvin Zhange50bb512022-08-01 15:58:51 -0700256 if OPTIONS.override_apk_keys is not None:
257 for apk in certmap.keys():
258 certmap[apk] = OPTIONS.override_apk_keys
259
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800260 # apply the key remapping to the contents of the file
Tao Baoa3705452019-06-24 15:33:41 -0700261 for apk, cert in certmap.items():
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800262 certmap[apk] = OPTIONS.key_map.get(cert, cert)
263
264 # apply all the -e options, overriding anything in the file
Tao Baoa3705452019-06-24 15:33:41 -0700265 for apk, cert in OPTIONS.extra_apks.items():
Doug Zongkerdecf9952009-12-15 17:27:49 -0800266 if not cert:
267 cert = "PRESIGNED"
Doug Zongkerad88c7c2009-04-14 12:34:27 -0700268 certmap[apk] = OPTIONS.key_map.get(cert, cert)
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800269
Doug Zongkereef39442009-04-02 12:14:19 -0700270 return certmap
271
272
Tao Baoaa7e9932019-03-15 09:37:01 -0700273def GetApexKeys(keys_info, key_map):
274 """Gets APEX payload and container signing keys by applying the mapping rules.
275
Tao Baoe1343992019-03-19 12:24:03 -0700276 Presigned payload / container keys will be set accordingly.
Tao Baoaa7e9932019-03-15 09:37:01 -0700277
278 Args:
279 keys_info: A dict that maps from APEX filenames to a tuple of (payload_key,
Jooyung Han8caba5e2021-10-27 03:58:09 +0900280 container_key, sign_tool).
Tao Baoaa7e9932019-03-15 09:37:01 -0700281 key_map: A dict that overrides the keys, specified via command-line input.
282
283 Returns:
284 A dict that contains the updated APEX key mapping, which should be used for
285 the current signing.
Tao Baof98fa102019-04-24 14:51:25 -0700286
287 Raises:
288 AssertionError: On invalid container / payload key overrides.
Tao Baoaa7e9932019-03-15 09:37:01 -0700289 """
Kelvin Zhange50bb512022-08-01 15:58:51 -0700290 if OPTIONS.override_apex_keys is not None:
291 for apex in keys_info.keys():
292 keys_info[apex] = (OPTIONS.override_apex_keys, keys_info[apex][1], keys_info[apex][2])
293
294 if OPTIONS.override_apk_keys is not None:
295 key = key_map.get(OPTIONS.override_apk_keys, OPTIONS.override_apk_keys)
296 for apex in keys_info.keys():
297 keys_info[apex] = (keys_info[apex][0], key, keys_info[apex][2])
298
Tao Baoaa7e9932019-03-15 09:37:01 -0700299 # Apply all the --extra_apex_payload_key options to override the payload
300 # signing keys in the given keys_info.
301 for apex, key in OPTIONS.extra_apex_payload_keys.items():
Tao Baoe1343992019-03-19 12:24:03 -0700302 if not key:
303 key = 'PRESIGNED'
Tao Bao34223092019-07-11 11:52:52 -0700304 if apex not in keys_info:
305 logger.warning('Failed to find %s in target_files; Ignored', apex)
306 continue
Jooyung Han8caba5e2021-10-27 03:58:09 +0900307 keys_info[apex] = (key, keys_info[apex][1], keys_info[apex][2])
Tao Baoaa7e9932019-03-15 09:37:01 -0700308
309 # Apply the key remapping to container keys.
Jooyung Han8caba5e2021-10-27 03:58:09 +0900310 for apex, (payload_key, container_key, sign_tool) in keys_info.items():
311 keys_info[apex] = (payload_key, key_map.get(container_key, container_key), sign_tool)
Tao Baoaa7e9932019-03-15 09:37:01 -0700312
313 # Apply all the --extra_apks options to override the container keys.
314 for apex, key in OPTIONS.extra_apks.items():
315 # Skip non-APEX containers.
316 if apex not in keys_info:
317 continue
Tao Baoe1343992019-03-19 12:24:03 -0700318 if not key:
319 key = 'PRESIGNED'
Jooyung Han8caba5e2021-10-27 03:58:09 +0900320 keys_info[apex] = (keys_info[apex][0], key_map.get(key, key), keys_info[apex][2])
Tao Baoaa7e9932019-03-15 09:37:01 -0700321
Tao Baof98fa102019-04-24 14:51:25 -0700322 # A PRESIGNED container entails a PRESIGNED payload. Apply this to all the
323 # APEX key pairs. However, a PRESIGNED container with non-PRESIGNED payload
324 # (overridden via commandline) indicates a config error, which should not be
325 # allowed.
Jooyung Han8caba5e2021-10-27 03:58:09 +0900326 for apex, (payload_key, container_key, sign_tool) in keys_info.items():
Tao Baof98fa102019-04-24 14:51:25 -0700327 if container_key != 'PRESIGNED':
328 continue
329 if apex in OPTIONS.extra_apex_payload_keys:
330 payload_override = OPTIONS.extra_apex_payload_keys[apex]
331 assert payload_override == '', \
332 ("Invalid APEX key overrides: {} has PRESIGNED container but "
333 "non-PRESIGNED payload key {}").format(apex, payload_override)
334 if payload_key != 'PRESIGNED':
335 print(
336 "Setting {} payload as PRESIGNED due to PRESIGNED container".format(
337 apex))
Jooyung Han8caba5e2021-10-27 03:58:09 +0900338 keys_info[apex] = ('PRESIGNED', 'PRESIGNED', None)
Tao Baof98fa102019-04-24 14:51:25 -0700339
Tao Baoaa7e9932019-03-15 09:37:01 -0700340 return keys_info
341
342
Tao Bao93c2a012018-06-19 12:19:35 -0700343def GetApkFileInfo(filename, compressed_extension, skipped_prefixes):
Tao Bao11f955c2018-06-19 12:19:35 -0700344 """Returns the APK info based on the given filename.
345
346 Checks if the given filename (with path) looks like an APK file, by taking the
Tao Bao93c2a012018-06-19 12:19:35 -0700347 compressed extension into consideration. If it appears to be an APK file,
348 further checks if the APK file should be skipped when signing, based on the
349 given path prefixes.
Tao Bao11f955c2018-06-19 12:19:35 -0700350
351 Args:
352 filename: Path to the file.
353 compressed_extension: The extension string of compressed APKs (e.g. ".gz"),
354 or None if there's no compressed APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700355 skipped_prefixes: A set/list/tuple of the path prefixes to be skipped.
Tao Bao11f955c2018-06-19 12:19:35 -0700356
357 Returns:
Tao Bao93c2a012018-06-19 12:19:35 -0700358 (is_apk, is_compressed, should_be_skipped): is_apk indicates whether the
359 given filename is an APK file. is_compressed indicates whether the APK file
360 is compressed (only meaningful when is_apk is True). should_be_skipped
361 indicates whether the filename matches any of the given prefixes to be
362 skipped.
Tao Bao11f955c2018-06-19 12:19:35 -0700363
364 Raises:
Tao Bao93c2a012018-06-19 12:19:35 -0700365 AssertionError: On invalid compressed_extension or skipped_prefixes inputs.
Tao Bao11f955c2018-06-19 12:19:35 -0700366 """
367 assert compressed_extension is None or compressed_extension.startswith('.'), \
368 "Invalid compressed_extension arg: '{}'".format(compressed_extension)
369
Tao Bao93c2a012018-06-19 12:19:35 -0700370 # skipped_prefixes should be one of set/list/tuple types. Other types such as
371 # str shouldn't be accepted.
Tao Baobadceb22019-03-15 09:33:43 -0700372 assert isinstance(skipped_prefixes, (set, list, tuple)), \
373 "Invalid skipped_prefixes input type: {}".format(type(skipped_prefixes))
Tao Bao93c2a012018-06-19 12:19:35 -0700374
Tao Bao11f955c2018-06-19 12:19:35 -0700375 compressed_apk_extension = (
376 ".apk" + compressed_extension if compressed_extension else None)
377 is_apk = (filename.endswith(".apk") or
378 (compressed_apk_extension and
379 filename.endswith(compressed_apk_extension)))
380 if not is_apk:
Tao Bao93c2a012018-06-19 12:19:35 -0700381 return (False, False, False)
Tao Bao11f955c2018-06-19 12:19:35 -0700382
383 is_compressed = (compressed_apk_extension and
384 filename.endswith(compressed_apk_extension))
Tao Bao93c2a012018-06-19 12:19:35 -0700385 should_be_skipped = filename.startswith(tuple(skipped_prefixes))
386 return (True, is_compressed, should_be_skipped)
Tao Bao11f955c2018-06-19 12:19:35 -0700387
388
Tao Baoaa7e9932019-03-15 09:37:01 -0700389def CheckApkAndApexKeysAvailable(input_tf_zip, known_keys,
Tao Baoe1343992019-03-19 12:24:03 -0700390 compressed_extension, apex_keys):
Tao Baoaa7e9932019-03-15 09:37:01 -0700391 """Checks that all the APKs and APEXes have keys specified.
Tao Bao11f955c2018-06-19 12:19:35 -0700392
393 Args:
394 input_tf_zip: An open target_files zip file.
Tao Baoaa7e9932019-03-15 09:37:01 -0700395 known_keys: A set of APKs and APEXes that have known signing keys.
Tao Bao11f955c2018-06-19 12:19:35 -0700396 compressed_extension: The extension string of compressed APKs, such as
Tao Baoaa7e9932019-03-15 09:37:01 -0700397 '.gz', or None if there's no compressed APKs.
Tao Baoe1343992019-03-19 12:24:03 -0700398 apex_keys: A dict that contains the key mapping from APEX name to
Jooyung Han8caba5e2021-10-27 03:58:09 +0900399 (payload_key, container_key, sign_tool).
Tao Bao11f955c2018-06-19 12:19:35 -0700400
401 Raises:
Tao Baoaa7e9932019-03-15 09:37:01 -0700402 AssertionError: On finding unknown APKs and APEXes.
Tao Bao11f955c2018-06-19 12:19:35 -0700403 """
Tao Baoaa7e9932019-03-15 09:37:01 -0700404 unknown_files = []
Doug Zongkereb338ef2009-05-20 16:50:49 -0700405 for info in input_tf_zip.infolist():
Tianjie5bd03952021-02-18 23:02:36 -0800406 # Handle APEXes on all partitions
Tianjie4d48d502021-06-11 17:03:43 -0700407 if IsApexFile(info.filename):
408 name = GetApexFilename(info.filename)
Tao Baoaa7e9932019-03-15 09:37:01 -0700409 if name not in known_keys:
410 unknown_files.append(name)
411 continue
412
413 # And APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700414 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
415 info.filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
416 if not is_apk or should_be_skipped:
Tao Bao11f955c2018-06-19 12:19:35 -0700417 continue
Tao Baoaa7e9932019-03-15 09:37:01 -0700418
Tao Bao11f955c2018-06-19 12:19:35 -0700419 name = os.path.basename(info.filename)
420 if is_compressed:
421 name = name[:-len(compressed_extension)]
Tao Baoaa7e9932019-03-15 09:37:01 -0700422 if name not in known_keys:
423 unknown_files.append(name)
Tao Bao11f955c2018-06-19 12:19:35 -0700424
Tao Baoaa7e9932019-03-15 09:37:01 -0700425 assert not unknown_files, \
Tao Bao11f955c2018-06-19 12:19:35 -0700426 ("No key specified for:\n {}\n"
427 "Use '-e <apkname>=' to specify a key (which may be an empty string to "
Tao Baoaa7e9932019-03-15 09:37:01 -0700428 "not sign this apk).".format("\n ".join(unknown_files)))
Doug Zongkereb338ef2009-05-20 16:50:49 -0700429
Tao Baoe1343992019-03-19 12:24:03 -0700430 # For all the APEXes, double check that we won't have an APEX that has only
Tao Baof98fa102019-04-24 14:51:25 -0700431 # one of the payload / container keys set. Note that non-PRESIGNED container
432 # with PRESIGNED payload could be allowed but currently unsupported. It would
433 # require changing SignApex implementation.
Tao Baoe1343992019-03-19 12:24:03 -0700434 if not apex_keys:
435 return
436
437 invalid_apexes = []
438 for info in input_tf_zip.infolist():
Tianjie4d48d502021-06-11 17:03:43 -0700439 if not IsApexFile(info.filename):
Tao Baoe1343992019-03-19 12:24:03 -0700440 continue
441
Tianjie4d48d502021-06-11 17:03:43 -0700442 name = GetApexFilename(info.filename)
443
Jooyung Han8caba5e2021-10-27 03:58:09 +0900444 (payload_key, container_key, _) = apex_keys[name]
Tao Baoe1343992019-03-19 12:24:03 -0700445 if ((payload_key in common.SPECIAL_CERT_STRINGS and
446 container_key not in common.SPECIAL_CERT_STRINGS) or
447 (payload_key not in common.SPECIAL_CERT_STRINGS and
448 container_key in common.SPECIAL_CERT_STRINGS)):
449 invalid_apexes.append(
450 "{}: payload_key {}, container_key {}".format(
451 name, payload_key, container_key))
452
453 assert not invalid_apexes, \
454 "Invalid APEX keys specified:\n {}\n".format(
455 "\n ".join(invalid_apexes))
456
Doug Zongkereb338ef2009-05-20 16:50:49 -0700457
Narayan Kamatha07bf042017-08-14 14:49:21 +0100458def SignApk(data, keyname, pw, platform_api_level, codename_to_api_level_map,
Oleg Aravin8046cb02020-06-02 16:02:38 -0700459 is_compressed, apk_name):
460 unsigned = tempfile.NamedTemporaryFile(suffix='_' + apk_name)
Doug Zongkereef39442009-04-02 12:14:19 -0700461 unsigned.write(data)
462 unsigned.flush()
463
Narayan Kamatha07bf042017-08-14 14:49:21 +0100464 if is_compressed:
465 uncompressed = tempfile.NamedTemporaryFile()
Tao Bao0c28d2d2017-12-24 10:37:38 -0800466 with gzip.open(unsigned.name, "rb") as in_file, \
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400467 open(uncompressed.name, "wb") as out_file:
Narayan Kamatha07bf042017-08-14 14:49:21 +0100468 shutil.copyfileobj(in_file, out_file)
469
470 # Finally, close the "unsigned" file (which is gzip compressed), and then
471 # replace it with the uncompressed version.
472 #
473 # TODO(narayan): All this nastiness can be avoided if python 3.2 is in use,
474 # we could just gzip / gunzip in-memory buffers instead.
475 unsigned.close()
476 unsigned = uncompressed
477
Oleg Aravin8046cb02020-06-02 16:02:38 -0700478 signed = tempfile.NamedTemporaryFile(suffix='_' + apk_name)
Doug Zongkereef39442009-04-02 12:14:19 -0700479
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800480 # For pre-N builds, don't upgrade to SHA-256 JAR signatures based on the APK's
481 # minSdkVersion to avoid increasing incremental OTA update sizes. If an APK
482 # didn't change, we don't want its signature to change due to the switch
483 # from SHA-1 to SHA-256.
484 # By default, APK signer chooses SHA-256 signatures if the APK's minSdkVersion
485 # is 18 or higher. For pre-N builds we disable this mechanism by pretending
486 # that the APK's minSdkVersion is 1.
487 # For N+ builds, we let APK signer rely on the APK's minSdkVersion to
488 # determine whether to use SHA-256.
489 min_api_level = None
490 if platform_api_level > 23:
491 # Let APK signer choose whether to use SHA-1 or SHA-256, based on the APK's
492 # minSdkVersion attribute
493 min_api_level = None
494 else:
495 # Force APK signer to use SHA-1
496 min_api_level = 1
497
498 common.SignFile(unsigned.name, signed.name, keyname, pw,
Tao Bao0c28d2d2017-12-24 10:37:38 -0800499 min_api_level=min_api_level,
500 codename_to_api_level_map=codename_to_api_level_map)
Doug Zongkereef39442009-04-02 12:14:19 -0700501
Tao Bao0c28d2d2017-12-24 10:37:38 -0800502 data = None
Narayan Kamatha07bf042017-08-14 14:49:21 +0100503 if is_compressed:
504 # Recompress the file after it has been signed.
505 compressed = tempfile.NamedTemporaryFile()
Tao Bao0c28d2d2017-12-24 10:37:38 -0800506 with open(signed.name, "rb") as in_file, \
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400507 gzip.open(compressed.name, "wb") as out_file:
Narayan Kamatha07bf042017-08-14 14:49:21 +0100508 shutil.copyfileobj(in_file, out_file)
509
510 data = compressed.read()
511 compressed.close()
512 else:
513 data = signed.read()
514
Doug Zongkereef39442009-04-02 12:14:19 -0700515 unsigned.close()
516 signed.close()
517
518 return data
519
Tianjie5bd03952021-02-18 23:02:36 -0800520
Kelvin Zhang119f2792021-02-10 12:45:24 -0500521def IsBuildPropFile(filename):
522 return filename in (
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400523 "SYSTEM/etc/prop.default",
524 "BOOT/RAMDISK/prop.default",
525 "RECOVERY/RAMDISK/prop.default",
Kelvin Zhang119f2792021-02-10 12:45:24 -0500526
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400527 "VENDOR_BOOT/RAMDISK/default.prop",
528 "VENDOR_BOOT/RAMDISK/prop.default",
Kelvin Zhang119f2792021-02-10 12:45:24 -0500529
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400530 # ROOT/default.prop is a legacy path, but may still exist for upgrading
531 # devices that don't support `property_overrides_split_enabled`.
532 "ROOT/default.prop",
Kelvin Zhang119f2792021-02-10 12:45:24 -0500533
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400534 # RECOVERY/RAMDISK/default.prop is a legacy path, but will always exist
535 # as a symlink in the current code. So it's a no-op here. Keeping the
536 # path here for clarity.
537 "RECOVERY/RAMDISK/default.prop") or filename.endswith("build.prop")
Doug Zongkereef39442009-04-02 12:14:19 -0700538
Tianjie5bd03952021-02-18 23:02:36 -0800539
Doug Zongker412c02f2014-02-13 10:58:24 -0800540def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -0700541 apk_keys, apex_keys, key_passwords,
542 platform_api_level, codename_to_api_level_map,
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +0000543 compressed_extension):
Tao Bao93c2a012018-06-19 12:19:35 -0700544 # maxsize measures the maximum filename length, including the ones to be
545 # skipped.
Bowgo Tsai8d4b7242022-01-04 15:15:35 +0800546 try:
547 maxsize = max(
548 [len(os.path.basename(i.filename)) for i in input_tf_zip.infolist()
549 if GetApkFileInfo(i.filename, compressed_extension, [])[0]])
550 except ValueError:
551 # Sets this to zero for targets without APK files, e.g., gki_arm64.
552 maxsize = 0
553
Tao Baoa80ed222016-06-16 14:41:24 -0700554 system_root_image = misc_info.get("system_root_image") == "true"
Doug Zongker412c02f2014-02-13 10:58:24 -0800555
Doug Zongkereef39442009-04-02 12:14:19 -0700556 for info in input_tf_zip.infolist():
Tao Bao11f955c2018-06-19 12:19:35 -0700557 filename = info.filename
558 if filename.startswith("IMAGES/"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700559 continue
Doug Zongker3c84f562014-07-31 11:06:30 -0700560
Tao Bao04808502019-07-25 23:11:41 -0700561 # Skip OTA-specific images (e.g. split super images), which will be
562 # re-generated during signing.
Tao Bao33bf2682019-01-11 12:37:35 -0800563 if filename.startswith("OTA/") and filename.endswith(".img"):
564 continue
565
Tao Bao11f955c2018-06-19 12:19:35 -0700566 data = input_tf_zip.read(filename)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700567 out_info = copy.copy(info)
Tao Bao93c2a012018-06-19 12:19:35 -0700568 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
569 filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
570
571 if is_apk and should_be_skipped:
572 # Copy skipped APKs verbatim.
573 print(
574 "NOT signing: %s\n"
575 " (skipped due to matching prefix)" % (filename,))
576 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker412c02f2014-02-13 10:58:24 -0800577
Tao Baof2cffbd2015-07-22 12:33:18 -0700578 # Sign APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700579 elif is_apk:
Tao Bao11f955c2018-06-19 12:19:35 -0700580 name = os.path.basename(filename)
Narayan Kamatha07bf042017-08-14 14:49:21 +0100581 if is_compressed:
582 name = name[:-len(compressed_extension)]
583
Tao Baoaa7e9932019-03-15 09:37:01 -0700584 key = apk_keys[name]
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800585 if key not in common.SPECIAL_CERT_STRINGS:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800586 print(" signing: %-*s (%s)" % (maxsize, name, key))
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800587 signed_data = SignApk(data, key, key_passwords[key], platform_api_level,
Oleg Aravin8046cb02020-06-02 16:02:38 -0700588 codename_to_api_level_map, is_compressed, name)
Tao Bao2ed665a2015-04-01 11:21:55 -0700589 common.ZipWriteStr(output_tf_zip, out_info, signed_data)
Doug Zongkereef39442009-04-02 12:14:19 -0700590 else:
591 # an APK we're not supposed to sign.
Tao Bao93c2a012018-06-19 12:19:35 -0700592 print(
593 "NOT signing: %s\n"
594 " (skipped due to special cert string)" % (name,))
Tao Bao2ed665a2015-04-01 11:21:55 -0700595 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoa80ed222016-06-16 14:41:24 -0700596
Tianjie5bd03952021-02-18 23:02:36 -0800597 # Sign bundled APEX files on all partitions
Tianjie4d48d502021-06-11 17:03:43 -0700598 elif IsApexFile(filename):
599 name = GetApexFilename(filename)
600
Jooyung Han8caba5e2021-10-27 03:58:09 +0900601 payload_key, container_key, sign_tool = apex_keys[name]
Tao Baoaa7e9932019-03-15 09:37:01 -0700602
Tao Baoe1343992019-03-19 12:24:03 -0700603 # We've asserted not having a case with only one of them PRESIGNED.
604 if (payload_key not in common.SPECIAL_CERT_STRINGS and
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400605 container_key not in common.SPECIAL_CERT_STRINGS):
Tao Baoe1343992019-03-19 12:24:03 -0700606 print(" signing: %-*s container (%s)" % (
607 maxsize, name, container_key))
608 print(" : %-*s payload (%s)" % (
609 maxsize, name, payload_key))
Tao Baoaa7e9932019-03-15 09:37:01 -0700610
Tao Baoe7354ba2019-05-09 16:54:15 -0700611 signed_apex = apex_utils.SignApex(
Tao Bao1ac886e2019-06-26 11:58:22 -0700612 misc_info['avb_avbtool'],
Tao Baoe1343992019-03-19 12:24:03 -0700613 data,
614 payload_key,
615 container_key,
Oleh Cherpake555ab12020-10-05 17:04:59 +0300616 key_passwords,
Tianjie Xu88a759d2020-01-23 10:47:54 -0800617 apk_keys,
Tao Baoe1343992019-03-19 12:24:03 -0700618 codename_to_api_level_map,
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400619 no_hashtree=None, # Let apex_util determine if hash tree is needed
Jooyung Han8caba5e2021-10-27 03:58:09 +0900620 signing_args=OPTIONS.avb_extra_args.get('apex'),
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +0000621 sign_tool=sign_tool)
Tao Baoe1343992019-03-19 12:24:03 -0700622 common.ZipWrite(output_tf_zip, signed_apex, filename)
Tao Baoaa7e9932019-03-15 09:37:01 -0700623
Tao Baoe1343992019-03-19 12:24:03 -0700624 else:
625 print(
626 "NOT signing: %s\n"
627 " (skipped due to special cert string)" % (name,))
628 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoaa7e9932019-03-15 09:37:01 -0700629
Tao Baoa80ed222016-06-16 14:41:24 -0700630 # System properties.
Kelvin Zhang119f2792021-02-10 12:45:24 -0500631 elif IsBuildPropFile(filename):
Tao Bao11f955c2018-06-19 12:19:35 -0700632 print("Rewriting %s:" % (filename,))
Hung-ying Tyan7eb6a922017-05-01 21:56:26 +0800633 if stat.S_ISLNK(info.external_attr >> 16):
634 new_data = data
635 else:
Tao Baoa3705452019-06-24 15:33:41 -0700636 new_data = RewriteProps(data.decode())
Tao Bao2ed665a2015-04-01 11:21:55 -0700637 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700638
Tao Bao66472632017-12-04 17:16:36 -0800639 # Replace the certs in *mac_permissions.xml (there could be multiple, such
Inseob Kime7b222a2021-12-21 15:57:03 +0900640 # as {system,vendor}/etc/selinux/{plat,vendor}_mac_permissions.xml).
Tao Bao11f955c2018-06-19 12:19:35 -0700641 elif filename.endswith("mac_permissions.xml"):
642 print("Rewriting %s with new keys." % (filename,))
Tao Baoa3705452019-06-24 15:33:41 -0700643 new_data = ReplaceCerts(data.decode())
Tao Bao2ed665a2015-04-01 11:21:55 -0700644 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700645
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700646 # Ask add_img_to_target_files to rebuild the recovery patch if needed.
Tao Bao11f955c2018-06-19 12:19:35 -0700647 elif filename in ("SYSTEM/recovery-from-boot.p",
Robin Leeda427de2020-01-03 19:16:32 +0100648 "VENDOR/recovery-from-boot.p",
649
Tao Bao11f955c2018-06-19 12:19:35 -0700650 "SYSTEM/etc/recovery.img",
Robin Leeda427de2020-01-03 19:16:32 +0100651 "VENDOR/etc/recovery.img",
652
653 "SYSTEM/bin/install-recovery.sh",
654 "VENDOR/bin/install-recovery.sh"):
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700655 OPTIONS.rebuild_recovery = True
Tao Baoa80ed222016-06-16 14:41:24 -0700656
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700657 # Don't copy OTA certs if we're replacing them.
Tianjie Xu2df23d72019-10-15 18:06:25 -0700658 # Replacement of update-payload-key.pub.pem was removed in b/116660991.
Kelvin Zhang9f781ff2021-02-11 19:10:44 -0500659 elif OPTIONS.replace_ota_keys and filename.endswith("/otacerts.zip"):
Doug Zongker412c02f2014-02-13 10:58:24 -0800660 pass
Tao Baoa80ed222016-06-16 14:41:24 -0700661
Tao Bao46a59992017-06-05 11:55:16 -0700662 # Skip META/misc_info.txt since we will write back the new values later.
Tao Bao11f955c2018-06-19 12:19:35 -0700663 elif filename == "META/misc_info.txt":
Geremy Condraf19b3652014-07-29 17:54:54 -0700664 pass
Tao Bao8adcfd12016-06-17 17:01:22 -0700665
666 # Skip verity public key if we will replace it.
Michael Runge947894f2014-10-14 20:58:38 -0700667 elif (OPTIONS.replace_verity_public_key and
Tao Bao11f955c2018-06-19 12:19:35 -0700668 filename in ("BOOT/RAMDISK/verity_key",
669 "ROOT/verity_key")):
Geremy Condraf19b3652014-07-29 17:54:54 -0700670 pass
Bowgo Tsai2fe786a2020-02-21 17:48:18 +0800671 elif (OPTIONS.remove_avb_public_keys and
672 (filename.startswith("BOOT/RAMDISK/avb/") or
673 filename.startswith("BOOT/RAMDISK/first_stage_ramdisk/avb/"))):
Kelvin Zhang0876c412020-06-23 15:06:58 -0400674 matched_removal = False
675 for key_to_remove in OPTIONS.remove_avb_public_keys:
676 if filename.endswith(key_to_remove):
677 matched_removal = True
678 print("Removing AVB public key from ramdisk: %s" % filename)
679 break
680 if not matched_removal:
681 # Copy it verbatim if we don't want to remove it.
682 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoa80ed222016-06-16 14:41:24 -0700683
Tao Bao8adcfd12016-06-17 17:01:22 -0700684 # Skip verity keyid (for system_root_image use) if we will replace it.
Tao Bao11f955c2018-06-19 12:19:35 -0700685 elif OPTIONS.replace_verity_keyid and filename == "BOOT/cmdline":
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700686 pass
687
Tianjiebbde59f2021-05-03 21:18:56 -0700688 # Skip the vbmeta digest as we will recalculate it.
689 elif filename == "META/vbmeta_digest.txt":
690 pass
691
Tianjie Xu4f099002016-08-11 18:04:27 -0700692 # Skip the care_map as we will regenerate the system/vendor images.
Kelvin Zhang0876c412020-06-23 15:06:58 -0400693 elif filename in ["META/care_map.pb", "META/care_map.txt"]:
Tianjie Xu4f099002016-08-11 18:04:27 -0700694 pass
695
Kelvin Zhang5f0fcee2021-01-19 15:30:46 -0500696 # Skip apex_info.pb because we sign/modify apexes
697 elif filename == "META/apex_info.pb":
698 pass
699
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800700 # Updates system_other.avbpubkey in /product/etc/.
701 elif filename in (
702 "PRODUCT/etc/security/avb/system_other.avbpubkey",
Bowgo Tsai2a781692021-10-13 17:39:33 +0800703 "SYSTEM/product/etc/security/avb/system_other.avbpubkey"):
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800704 # Only update system_other's public key, if the corresponding signing
705 # key is specified via --avb_system_other_key.
706 signing_key = OPTIONS.avb_keys.get("system_other")
707 if signing_key:
Tao Bao1ac886e2019-06-26 11:58:22 -0700708 public_key = common.ExtractAvbPublicKey(
709 misc_info['avb_avbtool'], signing_key)
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800710 print(" Rewriting AVB public key of system_other in /product")
711 common.ZipWrite(output_tf_zip, public_key, filename)
712
Andrew Scullbbc930b2022-02-17 22:34:27 +0000713 # Updates pvmfw embedded public key with the virt APEX payload key.
714 elif filename == "PREBUILT_IMAGES/pvmfw.img":
715 # Find the name of the virt APEX in the target files.
716 namelist = input_tf_zip.namelist()
717 apex_gen = (GetApexFilename(f) for f in namelist if IsApexFile(f))
718 virt_apex_re = re.compile("^com\.([^\.]+\.)?android\.virt\.apex$")
719 virt_apex = next((a for a in apex_gen if virt_apex_re.match(a)), None)
720 if not virt_apex:
721 print("Removing %s from ramdisk: virt APEX not found" % filename)
722 else:
723 print("Replacing %s embedded key with %s key" % (filename, virt_apex))
724 # Get the current and new embedded keys.
725 payload_key, container_key, sign_tool = apex_keys[virt_apex]
726 new_pubkey_path = common.ExtractAvbPublicKey(
727 misc_info['avb_avbtool'], payload_key)
728 with open(new_pubkey_path, 'rb') as f:
729 new_pubkey = f.read()
730 pubkey_info = copy.copy(
731 input_tf_zip.getinfo("PREBUILT_IMAGES/pvmfw_embedded.avbpubkey"))
732 old_pubkey = input_tf_zip.read(pubkey_info.filename)
733 # Validate the keys and image.
734 if len(old_pubkey) != len(new_pubkey):
735 raise common.ExternalError("pvmfw embedded public key size mismatch")
736 pos = data.find(old_pubkey)
737 if pos == -1:
738 raise common.ExternalError("pvmfw embedded public key not found")
739 # Replace the key and copy new files.
740 new_data = data[:pos] + new_pubkey + data[pos+len(old_pubkey):]
741 common.ZipWriteStr(output_tf_zip, out_info, new_data)
742 common.ZipWriteStr(output_tf_zip, pubkey_info, new_pubkey)
743 elif filename == "PREBUILT_IMAGES/pvmfw_embedded.avbpubkey":
744 pass
745
Bowgo Tsai78369eb2019-04-23 12:28:44 +0800746 # Should NOT sign boot-debug.img.
747 elif filename in (
748 "BOOT/RAMDISK/force_debuggable",
Bowgo Tsai2a781692021-10-13 17:39:33 +0800749 "BOOT/RAMDISK/first_stage_ramdisk/force_debuggable"):
Bowgo Tsai78369eb2019-04-23 12:28:44 +0800750 raise common.ExternalError("debuggable boot.img cannot be signed")
751
Bowgo Tsai2a781692021-10-13 17:39:33 +0800752 # Should NOT sign userdebug sepolicy file.
753 elif filename in (
754 "SYSTEM_EXT/etc/selinux/userdebug_plat_sepolicy.cil",
755 "SYSTEM/system_ext/etc/selinux/userdebug_plat_sepolicy.cil"):
756 if not OPTIONS.allow_gsi_debug_sepolicy:
757 raise common.ExternalError("debug sepolicy shouldn't be included")
758 else:
759 # Copy it verbatim if we allow the file to exist.
760 common.ZipWriteStr(output_tf_zip, out_info, data)
761
Tao Baoa80ed222016-06-16 14:41:24 -0700762 # A non-APK file; copy it verbatim.
Doug Zongkereef39442009-04-02 12:14:19 -0700763 else:
Tao Bao2ed665a2015-04-01 11:21:55 -0700764 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700765
Doug Zongker412c02f2014-02-13 10:58:24 -0800766 if OPTIONS.replace_ota_keys:
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700767 ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info)
Doug Zongker412c02f2014-02-13 10:58:24 -0800768
Tao Bao46a59992017-06-05 11:55:16 -0700769 # Replace the keyid string in misc_info dict.
Tao Bao8adcfd12016-06-17 17:01:22 -0700770 if OPTIONS.replace_verity_private_key:
Tao Bao46a59992017-06-05 11:55:16 -0700771 ReplaceVerityPrivateKey(misc_info, OPTIONS.replace_verity_private_key[1])
Tao Bao8adcfd12016-06-17 17:01:22 -0700772
773 if OPTIONS.replace_verity_public_key:
Tao Baoc9981932019-09-16 12:10:43 -0700774 # Replace the one in root dir in system.img.
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700775 ReplaceVerityPublicKey(
Tao Baoc9981932019-09-16 12:10:43 -0700776 output_tf_zip, 'ROOT/verity_key', OPTIONS.replace_verity_public_key[1])
777
778 if not system_root_image:
779 # Additionally replace the copy in ramdisk if not using system-as-root.
780 ReplaceVerityPublicKey(
781 output_tf_zip,
782 'BOOT/RAMDISK/verity_key',
783 OPTIONS.replace_verity_public_key[1])
Tao Bao8adcfd12016-06-17 17:01:22 -0700784
785 # Replace the keyid string in BOOT/cmdline.
786 if OPTIONS.replace_verity_keyid:
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700787 ReplaceVerityKeyId(input_tf_zip, output_tf_zip,
788 OPTIONS.replace_verity_keyid[1])
Doug Zongker412c02f2014-02-13 10:58:24 -0800789
Tao Bao639118f2017-06-19 15:48:02 -0700790 # Replace the AVB signing keys, if any.
791 ReplaceAvbSigningKeys(misc_info)
792
Tao Bao19b02fe2019-10-09 00:04:28 -0700793 # Rewrite the props in AVB signing args.
794 if misc_info.get('avb_enable') == 'true':
795 RewriteAvbProps(misc_info)
796
Bowgo Tsai27c39b02021-03-12 21:40:32 +0800797 # Replace the GKI signing key for boot.img, if any.
798 ReplaceGkiSigningKey(misc_info)
799
Tao Bao46a59992017-06-05 11:55:16 -0700800 # Write back misc_info with the latest values.
801 ReplaceMiscInfoTxt(input_tf_zip, output_tf_zip, misc_info)
802
Doug Zongker8e931bf2009-04-06 15:21:45 -0700803
Robert Craig817c5742013-04-19 10:59:22 -0400804def ReplaceCerts(data):
Tao Bao66472632017-12-04 17:16:36 -0800805 """Replaces all the occurences of X.509 certs with the new ones.
Robert Craig817c5742013-04-19 10:59:22 -0400806
Tao Bao66472632017-12-04 17:16:36 -0800807 The mapping info is read from OPTIONS.key_map. Non-existent certificate will
808 be skipped. After the replacement, it additionally checks for duplicate
809 entries, which would otherwise fail the policy loading code in
810 frameworks/base/services/core/java/com/android/server/pm/SELinuxMMAC.java.
811
812 Args:
813 data: Input string that contains a set of X.509 certs.
814
815 Returns:
816 A string after the replacement.
817
818 Raises:
819 AssertionError: On finding duplicate entries.
820 """
Tao Baoa3705452019-06-24 15:33:41 -0700821 for old, new in OPTIONS.key_map.items():
Tao Bao66472632017-12-04 17:16:36 -0800822 if OPTIONS.verbose:
823 print(" Replacing %s.x509.pem with %s.x509.pem" % (old, new))
824
825 try:
826 with open(old + ".x509.pem") as old_fp:
827 old_cert16 = base64.b16encode(
Tao Baoa3705452019-06-24 15:33:41 -0700828 common.ParseCertificate(old_fp.read())).decode().lower()
Tao Bao66472632017-12-04 17:16:36 -0800829 with open(new + ".x509.pem") as new_fp:
830 new_cert16 = base64.b16encode(
Tao Baoa3705452019-06-24 15:33:41 -0700831 common.ParseCertificate(new_fp.read())).decode().lower()
Tao Bao66472632017-12-04 17:16:36 -0800832 except IOError as e:
833 if OPTIONS.verbose or e.errno != errno.ENOENT:
834 print(" Error accessing %s: %s.\nSkip replacing %s.x509.pem with "
835 "%s.x509.pem." % (e.filename, e.strerror, old, new))
836 continue
837
838 # Only match entire certs.
839 pattern = "\\b" + old_cert16 + "\\b"
840 (data, num) = re.subn(pattern, new_cert16, data, flags=re.IGNORECASE)
841
842 if OPTIONS.verbose:
843 print(" Replaced %d occurence(s) of %s.x509.pem with %s.x509.pem" % (
844 num, old, new))
845
846 # Verify that there're no duplicate entries after the replacement. Note that
847 # it's only checking entries with global seinfo at the moment (i.e. ignoring
848 # the ones with inner packages). (Bug: 69479366)
849 root = ElementTree.fromstring(data)
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400850 signatures = [signer.attrib['signature']
851 for signer in root.findall('signer')]
Tao Bao66472632017-12-04 17:16:36 -0800852 assert len(signatures) == len(set(signatures)), \
853 "Found duplicate entries after cert replacement: {}".format(data)
Robert Craig817c5742013-04-19 10:59:22 -0400854
855 return data
856
857
Doug Zongkerc09abc82010-01-11 13:09:15 -0800858def EditTags(tags):
Tao Baoa7054ee2017-12-08 14:42:16 -0800859 """Applies the edits to the tag string as specified in OPTIONS.tag_changes.
860
861 Args:
862 tags: The input string that contains comma-separated tags.
863
864 Returns:
865 The updated tags (comma-separated and sorted).
866 """
Doug Zongkerc09abc82010-01-11 13:09:15 -0800867 tags = set(tags.split(","))
868 for ch in OPTIONS.tag_changes:
869 if ch[0] == "-":
870 tags.discard(ch[1:])
871 elif ch[0] == "+":
872 tags.add(ch[1:])
873 return ",".join(sorted(tags))
874
875
Tao Baoa7054ee2017-12-08 14:42:16 -0800876def RewriteProps(data):
877 """Rewrites the system properties in the given string.
878
879 Each property is expected in 'key=value' format. The properties that contain
880 build tags (i.e. test-keys, dev-keys) will be updated accordingly by calling
881 EditTags().
882
883 Args:
884 data: Input string, separated by newlines.
885
886 Returns:
887 The string with modified properties.
888 """
Doug Zongker17aa9442009-04-17 10:15:58 -0700889 output = []
890 for line in data.split("\n"):
891 line = line.strip()
892 original_line = line
Michael Rungedc2661a2014-06-03 14:43:11 -0700893 if line and line[0] != '#' and "=" in line:
Doug Zongker17aa9442009-04-17 10:15:58 -0700894 key, value = line.split("=", 1)
Magnus Strandh234f4b42019-05-01 23:09:30 +0200895 if (key.startswith("ro.") and
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400896 key.endswith((".build.fingerprint", ".build.thumbprint"))):
Doug Zongkerc09abc82010-01-11 13:09:15 -0800897 pieces = value.split("/")
898 pieces[-1] = EditTags(pieces[-1])
899 value = "/".join(pieces)
Tao Baocb7ff772015-09-11 15:27:56 -0700900 elif key == "ro.bootimage.build.fingerprint":
901 pieces = value.split("/")
902 pieces[-1] = EditTags(pieces[-1])
903 value = "/".join(pieces)
Doug Zongker17aa9442009-04-17 10:15:58 -0700904 elif key == "ro.build.description":
jiajia tange5ddfcd2022-06-21 10:36:12 +0800905 pieces = value.split()
Stefen Wakefield4260fc12021-03-23 04:58:22 -0500906 assert pieces[-1].endswith("-keys")
Doug Zongkerc09abc82010-01-11 13:09:15 -0800907 pieces[-1] = EditTags(pieces[-1])
908 value = " ".join(pieces)
Magnus Strandh234f4b42019-05-01 23:09:30 +0200909 elif key.startswith("ro.") and key.endswith(".build.tags"):
Doug Zongkerc09abc82010-01-11 13:09:15 -0800910 value = EditTags(value)
Doug Zongkera8608a72013-07-23 11:51:04 -0700911 elif key == "ro.build.display.id":
912 # change, eg, "JWR66N dev-keys" to "JWR66N"
913 value = value.split()
Michael Rungedc2661a2014-06-03 14:43:11 -0700914 if len(value) > 1 and value[-1].endswith("-keys"):
Andrew Boie73d5abb2013-12-11 12:42:03 -0800915 value.pop()
916 value = " ".join(value)
Doug Zongkerc09abc82010-01-11 13:09:15 -0800917 line = key + "=" + value
Doug Zongker17aa9442009-04-17 10:15:58 -0700918 if line != original_line:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800919 print(" replace: ", original_line)
920 print(" with: ", line)
Doug Zongker17aa9442009-04-17 10:15:58 -0700921 output.append(line)
922 return "\n".join(output) + "\n"
923
924
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700925def WriteOtacerts(output_zip, filename, keys):
926 """Constructs a zipfile from given keys; and writes it to output_zip.
927
928 Args:
929 output_zip: The output target_files zip.
930 filename: The archive name in the output zip.
931 keys: A list of public keys to use during OTA package verification.
932 """
Tao Baobb733882019-07-24 23:31:19 -0700933 temp_file = io.BytesIO()
Kelvin Zhang928c2342020-09-22 16:15:57 -0400934 certs_zip = zipfile.ZipFile(temp_file, "w", allowZip64=True)
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700935 for k in keys:
936 common.ZipWrite(certs_zip, k)
937 common.ZipClose(certs_zip)
938 common.ZipWriteStr(output_zip, filename, temp_file.getvalue())
939
940
Doug Zongker831840e2011-09-22 10:28:04 -0700941def ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info):
Doug Zongker8e931bf2009-04-06 15:21:45 -0700942 try:
943 keylist = input_tf_zip.read("META/otakeys.txt").split()
944 except KeyError:
T.R. Fullharta28acc62013-03-18 10:31:26 -0700945 raise common.ExternalError("can't read META/otakeys.txt from input")
Doug Zongker8e931bf2009-04-06 15:21:45 -0700946
Jacky Liubeb0b692021-12-29 16:29:05 +0800947 extra_ota_keys_info = misc_info.get("extra_ota_keys")
948 if extra_ota_keys_info:
949 extra_ota_keys = [OPTIONS.key_map.get(k, k) + ".x509.pem"
950 for k in extra_ota_keys_info.split()]
951 print("extra ota key(s): " + ", ".join(extra_ota_keys))
952 else:
953 extra_ota_keys = []
954 for k in extra_ota_keys:
955 if not os.path.isfile(k):
956 raise common.ExternalError(k + " does not exist or is not a file")
957
958 extra_recovery_keys_info = misc_info.get("extra_recovery_keys")
959 if extra_recovery_keys_info:
Doug Zongkere121d6a2011-02-01 14:13:52 -0800960 extra_recovery_keys = [OPTIONS.key_map.get(k, k) + ".x509.pem"
Jacky Liubeb0b692021-12-29 16:29:05 +0800961 for k in extra_recovery_keys_info.split()]
962 print("extra recovery-only key(s): " + ", ".join(extra_recovery_keys))
Doug Zongkere121d6a2011-02-01 14:13:52 -0800963 else:
964 extra_recovery_keys = []
Jacky Liubeb0b692021-12-29 16:29:05 +0800965 for k in extra_recovery_keys:
966 if not os.path.isfile(k):
967 raise common.ExternalError(k + " does not exist or is not a file")
Doug Zongkere121d6a2011-02-01 14:13:52 -0800968
Doug Zongker8e931bf2009-04-06 15:21:45 -0700969 mapped_keys = []
970 for k in keylist:
971 m = re.match(r"^(.*)\.x509\.pem$", k)
972 if not m:
Doug Zongker412c02f2014-02-13 10:58:24 -0800973 raise common.ExternalError(
974 "can't parse \"%s\" from META/otakeys.txt" % (k,))
Doug Zongker8e931bf2009-04-06 15:21:45 -0700975 k = m.group(1)
976 mapped_keys.append(OPTIONS.key_map.get(k, k) + ".x509.pem")
977
Doug Zongkere05628c2009-08-20 17:38:42 -0700978 if mapped_keys:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800979 print("using:\n ", "\n ".join(mapped_keys))
980 print("for OTA package verification")
Doug Zongkere05628c2009-08-20 17:38:42 -0700981 else:
Doug Zongker831840e2011-09-22 10:28:04 -0700982 devkey = misc_info.get("default_system_dev_certificate",
Dan Willemsen0ab1be62019-04-09 21:35:37 -0700983 "build/make/target/product/security/testkey")
Tao Baof718f902017-11-09 10:10:10 -0800984 mapped_devkey = OPTIONS.key_map.get(devkey, devkey)
985 if mapped_devkey != devkey:
986 misc_info["default_system_dev_certificate"] = mapped_devkey
987 mapped_keys.append(mapped_devkey + ".x509.pem")
Tao Baoa80ed222016-06-16 14:41:24 -0700988 print("META/otakeys.txt has no keys; using %s for OTA package"
989 " verification." % (mapped_keys[0],))
Jacky Liubeb0b692021-12-29 16:29:05 +0800990 for k in mapped_keys:
991 if not os.path.isfile(k):
992 raise common.ExternalError(k + " does not exist or is not a file")
Doug Zongker8e931bf2009-04-06 15:21:45 -0700993
Kelvin Zhang9f781ff2021-02-11 19:10:44 -0500994 otacerts = [info
995 for info in input_tf_zip.infolist()
996 if info.filename.endswith("/otacerts.zip")]
997 for info in otacerts:
Jacky Liubeb0b692021-12-29 16:29:05 +0800998 if info.filename.startswith(("BOOT/", "RECOVERY/", "VENDOR_BOOT/")):
999 extra_keys = extra_recovery_keys
1000 else:
1001 extra_keys = extra_ota_keys
1002 print("Rewriting OTA key:", info.filename, mapped_keys + extra_keys)
1003 WriteOtacerts(output_tf_zip, info.filename, mapped_keys + extra_keys)
Doug Zongkereef39442009-04-02 12:14:19 -07001004
Tao Baoa80ed222016-06-16 14:41:24 -07001005
Tao Bao0c28d2d2017-12-24 10:37:38 -08001006def ReplaceVerityPublicKey(output_zip, filename, key_path):
1007 """Replaces the verity public key at the given path in the given zip.
1008
1009 Args:
1010 output_zip: The output target_files zip.
1011 filename: The archive name in the output zip.
1012 key_path: The path to the public key.
1013 """
1014 print("Replacing verity public key with %s" % (key_path,))
1015 common.ZipWrite(output_zip, key_path, arcname=filename)
Geremy Condraf19b3652014-07-29 17:54:54 -07001016
Tao Bao8adcfd12016-06-17 17:01:22 -07001017
Tao Bao46a59992017-06-05 11:55:16 -07001018def ReplaceVerityPrivateKey(misc_info, key_path):
Tao Bao0c28d2d2017-12-24 10:37:38 -08001019 """Replaces the verity private key in misc_info dict.
1020
1021 Args:
1022 misc_info: The info dict.
1023 key_path: The path to the private key in PKCS#8 format.
1024 """
1025 print("Replacing verity private key with %s" % (key_path,))
Andrew Boied083f0b2014-09-15 16:01:07 -07001026 misc_info["verity_key"] = key_path
Doug Zongkereef39442009-04-02 12:14:19 -07001027
Tao Bao8adcfd12016-06-17 17:01:22 -07001028
Tao Baoe838d142017-12-23 23:44:48 -08001029def ReplaceVerityKeyId(input_zip, output_zip, key_path):
1030 """Replaces the veritykeyid parameter in BOOT/cmdline.
1031
1032 Args:
1033 input_zip: The input target_files zip, which should be already open.
1034 output_zip: The output target_files zip, which should be already open and
1035 writable.
1036 key_path: The path to the PEM encoded X.509 certificate.
1037 """
Tao Baoa3705452019-06-24 15:33:41 -07001038 in_cmdline = input_zip.read("BOOT/cmdline").decode()
Tao Baoe838d142017-12-23 23:44:48 -08001039 # Copy in_cmdline to output_zip if veritykeyid is not present.
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001040 if "veritykeyid" not in in_cmdline:
Tao Baoe838d142017-12-23 23:44:48 -08001041 common.ZipWriteStr(output_zip, "BOOT/cmdline", in_cmdline)
1042 return
1043
Tao Bao0c28d2d2017-12-24 10:37:38 -08001044 out_buffer = []
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001045 for param in in_cmdline.split():
Tao Baoe838d142017-12-23 23:44:48 -08001046 if "veritykeyid" not in param:
Tao Bao0c28d2d2017-12-24 10:37:38 -08001047 out_buffer.append(param)
Tao Baoe838d142017-12-23 23:44:48 -08001048 continue
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001049
Tao Baoe838d142017-12-23 23:44:48 -08001050 # Extract keyid using openssl command.
1051 p = common.Run(["openssl", "x509", "-in", key_path, "-text"],
Tao Baode1d4792018-02-20 10:05:46 -08001052 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
Tao Baoe838d142017-12-23 23:44:48 -08001053 keyid, stderr = p.communicate()
1054 assert p.returncode == 0, "Failed to dump certificate: {}".format(stderr)
1055 keyid = re.search(
1056 r'keyid:([0-9a-fA-F:]*)', keyid).group(1).replace(':', '').lower()
1057 print("Replacing verity keyid with {}".format(keyid))
1058 out_buffer.append("veritykeyid=id:%s" % (keyid,))
1059
1060 out_cmdline = ' '.join(out_buffer).strip() + '\n'
1061 common.ZipWriteStr(output_zip, "BOOT/cmdline", out_cmdline)
Tao Bao46a59992017-06-05 11:55:16 -07001062
1063
1064def ReplaceMiscInfoTxt(input_zip, output_zip, misc_info):
1065 """Replaces META/misc_info.txt.
1066
1067 Only writes back the ones in the original META/misc_info.txt. Because the
1068 current in-memory dict contains additional items computed at runtime.
1069 """
1070 misc_info_old = common.LoadDictionaryFromLines(
Tao Baoa3705452019-06-24 15:33:41 -07001071 input_zip.read('META/misc_info.txt').decode().split('\n'))
Tao Bao46a59992017-06-05 11:55:16 -07001072 items = []
1073 for key in sorted(misc_info):
1074 if key in misc_info_old:
1075 items.append('%s=%s' % (key, misc_info[key]))
1076 common.ZipWriteStr(output_zip, "META/misc_info.txt", '\n'.join(items))
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001077
Tao Bao8adcfd12016-06-17 17:01:22 -07001078
Tao Bao639118f2017-06-19 15:48:02 -07001079def ReplaceAvbSigningKeys(misc_info):
1080 """Replaces the AVB signing keys."""
1081
Tao Bao639118f2017-06-19 15:48:02 -07001082 def ReplaceAvbPartitionSigningKey(partition):
1083 key = OPTIONS.avb_keys.get(partition)
1084 if not key:
1085 return
1086
1087 algorithm = OPTIONS.avb_algorithms.get(partition)
1088 assert algorithm, 'Missing AVB signing algorithm for %s' % (partition,)
1089
Tao Bao0c28d2d2017-12-24 10:37:38 -08001090 print('Replacing AVB signing key for %s with "%s" (%s)' % (
1091 partition, key, algorithm))
Tao Bao639118f2017-06-19 15:48:02 -07001092 misc_info['avb_' + partition + '_algorithm'] = algorithm
1093 misc_info['avb_' + partition + '_key_path'] = key
1094
1095 extra_args = OPTIONS.avb_extra_args.get(partition)
1096 if extra_args:
Tao Bao0c28d2d2017-12-24 10:37:38 -08001097 print('Setting extra AVB signing args for %s to "%s"' % (
1098 partition, extra_args))
Kelvin Zhang0876c412020-06-23 15:06:58 -04001099 args_key = AVB_FOOTER_ARGS_BY_PARTITION.get(
1100 partition,
1101 # custom partition
1102 "avb_{}_add_hashtree_footer_args".format(partition))
Tao Bao639118f2017-06-19 15:48:02 -07001103 misc_info[args_key] = (misc_info.get(args_key, '') + ' ' + extra_args)
1104
1105 for partition in AVB_FOOTER_ARGS_BY_PARTITION:
1106 ReplaceAvbPartitionSigningKey(partition)
1107
Hongguang Chenf23364d2020-04-27 18:36:36 -07001108 for custom_partition in misc_info.get(
Kelvin Zhang7cab7502021-08-02 19:58:14 -04001109 "avb_custom_images_partition_list", "").strip().split():
Hongguang Chenf23364d2020-04-27 18:36:36 -07001110 ReplaceAvbPartitionSigningKey(custom_partition)
1111
Tao Bao639118f2017-06-19 15:48:02 -07001112
Tao Bao19b02fe2019-10-09 00:04:28 -07001113def RewriteAvbProps(misc_info):
1114 """Rewrites the props in AVB signing args."""
1115 for partition, args_key in AVB_FOOTER_ARGS_BY_PARTITION.items():
1116 args = misc_info.get(args_key)
1117 if not args:
1118 continue
1119
1120 tokens = []
1121 changed = False
jiajia tange5ddfcd2022-06-21 10:36:12 +08001122 for token in args.split():
Tao Bao19b02fe2019-10-09 00:04:28 -07001123 fingerprint_key = 'com.android.build.{}.fingerprint'.format(partition)
1124 if not token.startswith(fingerprint_key):
1125 tokens.append(token)
1126 continue
1127 prefix, tag = token.rsplit('/', 1)
1128 tokens.append('{}/{}'.format(prefix, EditTags(tag)))
1129 changed = True
1130
1131 if changed:
1132 result = ' '.join(tokens)
1133 print('Rewriting AVB prop for {}:\n'.format(partition))
1134 print(' replace: {}'.format(args))
1135 print(' with: {}'.format(result))
1136 misc_info[args_key] = result
1137
1138
Bowgo Tsai27c39b02021-03-12 21:40:32 +08001139def ReplaceGkiSigningKey(misc_info):
1140 """Replaces the GKI signing key."""
1141
1142 key = OPTIONS.gki_signing_key
1143 if not key:
1144 return
1145
1146 algorithm = OPTIONS.gki_signing_algorithm
1147 if not algorithm:
1148 raise ValueError("Missing --gki_signing_algorithm")
1149
1150 print('Replacing GKI signing key with "%s" (%s)' % (key, algorithm))
1151 misc_info["gki_signing_algorithm"] = algorithm
1152 misc_info["gki_signing_key_path"] = key
1153
1154 extra_args = OPTIONS.gki_signing_extra_args
1155 if extra_args:
Bowgo Tsaibcae74d2021-05-10 17:35:37 +08001156 print('Setting GKI signing args: "%s"' % (extra_args))
1157 misc_info["gki_signing_signature_args"] = extra_args
Bowgo Tsai27c39b02021-03-12 21:40:32 +08001158
1159
Doug Zongker831840e2011-09-22 10:28:04 -07001160def BuildKeyMap(misc_info, key_mapping_options):
1161 for s, d in key_mapping_options:
1162 if s is None: # -d option
1163 devkey = misc_info.get("default_system_dev_certificate",
Dan Willemsen0ab1be62019-04-09 21:35:37 -07001164 "build/make/target/product/security/testkey")
Doug Zongker831840e2011-09-22 10:28:04 -07001165 devkeydir = os.path.dirname(devkey)
1166
1167 OPTIONS.key_map.update({
1168 devkeydir + "/testkey": d + "/releasekey",
1169 devkeydir + "/devkey": d + "/releasekey",
1170 devkeydir + "/media": d + "/media",
1171 devkeydir + "/shared": d + "/shared",
1172 devkeydir + "/platform": d + "/platform",
Oleh Cherpak982e6082019-12-10 12:58:54 +02001173 devkeydir + "/networkstack": d + "/networkstack",
Kelvin Zhang7cab7502021-08-02 19:58:14 -04001174 })
Doug Zongker831840e2011-09-22 10:28:04 -07001175 else:
1176 OPTIONS.key_map[s] = d
1177
1178
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001179def GetApiLevelAndCodename(input_tf_zip):
Tao Baoa3705452019-06-24 15:33:41 -07001180 data = input_tf_zip.read("SYSTEM/build.prop").decode()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001181 api_level = None
1182 codename = None
1183 for line in data.split("\n"):
1184 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001185 if line and line[0] != '#' and "=" in line:
1186 key, value = line.split("=", 1)
1187 key = key.strip()
1188 if key == "ro.build.version.sdk":
1189 api_level = int(value.strip())
1190 elif key == "ro.build.version.codename":
1191 codename = value.strip()
1192
1193 if api_level is None:
1194 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
1195 if codename is None:
1196 raise ValueError("No ro.build.version.codename in SYSTEM/build.prop")
1197
1198 return (api_level, codename)
1199
1200
1201def GetCodenameToApiLevelMap(input_tf_zip):
Tao Baoa3705452019-06-24 15:33:41 -07001202 data = input_tf_zip.read("SYSTEM/build.prop").decode()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001203 api_level = None
1204 codenames = None
1205 for line in data.split("\n"):
1206 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001207 if line and line[0] != '#' and "=" in line:
1208 key, value = line.split("=", 1)
1209 key = key.strip()
1210 if key == "ro.build.version.sdk":
1211 api_level = int(value.strip())
1212 elif key == "ro.build.version.all_codenames":
1213 codenames = value.strip().split(",")
1214
1215 if api_level is None:
1216 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
1217 if codenames is None:
1218 raise ValueError("No ro.build.version.all_codenames in SYSTEM/build.prop")
1219
Tao Baoa3705452019-06-24 15:33:41 -07001220 result = {}
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001221 for codename in codenames:
1222 codename = codename.strip()
Tao Baobadceb22019-03-15 09:33:43 -07001223 if codename:
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001224 result[codename] = api_level
1225 return result
1226
1227
Tao Baoaa7e9932019-03-15 09:37:01 -07001228def ReadApexKeysInfo(tf_zip):
1229 """Parses the APEX keys info from a given target-files zip.
1230
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001231 Given a target-files ZipFile, parses the META/apexkeys.txt entry and returns a
1232 dict that contains the mapping from APEX names (e.g. com.android.tzdata) to a
1233 tuple of (payload_key, container_key, sign_tool).
Tao Baoaa7e9932019-03-15 09:37:01 -07001234
1235 Args:
1236 tf_zip: The input target_files ZipFile (already open).
1237
1238 Returns:
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001239 (payload_key, container_key, sign_tool):
Jooyung Han8caba5e2021-10-27 03:58:09 +09001240 - payload_key contains the path to the payload signing key
1241 - container_key contains the path to the container signing key
1242 - sign_tool is an apex-specific signing tool for its payload contents
Tao Baoaa7e9932019-03-15 09:37:01 -07001243 """
1244 keys = {}
Tao Baoa3705452019-06-24 15:33:41 -07001245 for line in tf_zip.read('META/apexkeys.txt').decode().split('\n'):
Tao Baoaa7e9932019-03-15 09:37:01 -07001246 line = line.strip()
1247 if not line:
1248 continue
1249 matches = re.match(
1250 r'^name="(?P<NAME>.*)"\s+'
1251 r'public_key="(?P<PAYLOAD_PUBLIC_KEY>.*)"\s+'
1252 r'private_key="(?P<PAYLOAD_PRIVATE_KEY>.*)"\s+'
1253 r'container_certificate="(?P<CONTAINER_CERT>.*)"\s+'
Bill Peckham5c7b0342020-04-03 15:36:23 -07001254 r'container_private_key="(?P<CONTAINER_PRIVATE_KEY>.*?)"'
Jooyung Han8caba5e2021-10-27 03:58:09 +09001255 r'(\s+partition="(?P<PARTITION>.*?)")?'
1256 r'(\s+sign_tool="(?P<SIGN_TOOL>.*?)")?$',
Tao Baoaa7e9932019-03-15 09:37:01 -07001257 line)
1258 if not matches:
1259 continue
1260
1261 name = matches.group('NAME')
Tao Baoaa7e9932019-03-15 09:37:01 -07001262 payload_private_key = matches.group("PAYLOAD_PRIVATE_KEY")
1263
1264 def CompareKeys(pubkey, pubkey_suffix, privkey, privkey_suffix):
1265 pubkey_suffix_len = len(pubkey_suffix)
1266 privkey_suffix_len = len(privkey_suffix)
1267 return (pubkey.endswith(pubkey_suffix) and
1268 privkey.endswith(privkey_suffix) and
1269 pubkey[:-pubkey_suffix_len] == privkey[:-privkey_suffix_len])
1270
Ivan Lozanob021b2a2020-07-28 09:31:06 -04001271 # Check the container key names, as we'll carry them without the
Tao Bao6d9e3da2019-03-26 12:59:25 -07001272 # extensions. This doesn't apply to payload keys though, which we will use
1273 # full names only.
Tao Baoaa7e9932019-03-15 09:37:01 -07001274 container_cert = matches.group("CONTAINER_CERT")
1275 container_private_key = matches.group("CONTAINER_PRIVATE_KEY")
Tao Baof454c3a2019-04-24 23:53:42 -07001276 if container_cert == 'PRESIGNED' and container_private_key == 'PRESIGNED':
1277 container_key = 'PRESIGNED'
1278 elif CompareKeys(
Kelvin Zhang7cab7502021-08-02 19:58:14 -04001279 container_cert, OPTIONS.public_key_suffix,
1280 container_private_key, OPTIONS.private_key_suffix):
Tao Baof454c3a2019-04-24 23:53:42 -07001281 container_key = container_cert[:-len(OPTIONS.public_key_suffix)]
1282 else:
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001283 raise ValueError("Failed to parse container keys: \n{}".format(line))
Tao Baoaa7e9932019-03-15 09:37:01 -07001284
Jooyung Han8caba5e2021-10-27 03:58:09 +09001285 sign_tool = matches.group("SIGN_TOOL")
1286 keys[name] = (payload_private_key, container_key, sign_tool)
Tao Baoaa7e9932019-03-15 09:37:01 -07001287
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001288 return keys
Tao Baoaa7e9932019-03-15 09:37:01 -07001289
1290
Daniel Norman78554ea2021-09-14 10:29:38 -07001291def BuildVendorPartitions(output_zip_path):
1292 """Builds OPTIONS.vendor_partitions using OPTIONS.vendor_otatools."""
1293 if OPTIONS.vendor_partitions.difference(ALLOWED_VENDOR_PARTITIONS):
1294 logger.warning("Allowed --vendor_partitions: %s",
1295 ",".join(ALLOWED_VENDOR_PARTITIONS))
1296 OPTIONS.vendor_partitions = ALLOWED_VENDOR_PARTITIONS.intersection(
1297 OPTIONS.vendor_partitions)
1298
1299 logger.info("Building vendor partitions using vendor otatools.")
1300 vendor_tempdir = common.UnzipTemp(output_zip_path, [
1301 "META/*",
Po Hu0663ae42021-09-27 12:59:06 +08001302 "SYSTEM/build.prop",
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001303 "RECOVERY/*",
1304 "BOOT/*",
1305 "OTA/",
Daniel Norman78554ea2021-09-14 10:29:38 -07001306 ] + ["{}/*".format(p.upper()) for p in OPTIONS.vendor_partitions])
1307
1308 # Disable various partitions that build based on misc_info fields.
1309 # Only partitions in ALLOWED_VENDOR_PARTITIONS can be rebuilt using
1310 # vendor otatools. These other partitions will be rebuilt using the main
1311 # otatools if necessary.
1312 vendor_misc_info_path = os.path.join(vendor_tempdir, "META/misc_info.txt")
1313 vendor_misc_info = common.LoadDictionaryFromFile(vendor_misc_info_path)
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001314 # Ignore if not rebuilding recovery
1315 if not OPTIONS.rebuild_recovery:
1316 vendor_misc_info["no_boot"] = "true" # boot
1317 vendor_misc_info["vendor_boot"] = "false" # vendor_boot
1318 vendor_misc_info["no_recovery"] = "true" # recovery
Iavor-Valentin Iftime40adb172022-04-19 18:17:56 +00001319 vendor_misc_info["avb_enable"] = "false" # vbmeta
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001320
Daniel Norman78554ea2021-09-14 10:29:38 -07001321 vendor_misc_info["board_bpt_enable"] = "false" # partition-table
1322 vendor_misc_info["has_dtbo"] = "false" # dtbo
1323 vendor_misc_info["has_pvmfw"] = "false" # pvmfw
1324 vendor_misc_info["avb_custom_images_partition_list"] = "" # custom images
Iavor-Valentin Iftime40adb172022-04-19 18:17:56 +00001325 vendor_misc_info["avb_building_vbmeta_image"] = "false" # skip building vbmeta
Daniel Norman78554ea2021-09-14 10:29:38 -07001326 vendor_misc_info["use_dynamic_partitions"] = "false" # super_empty
1327 vendor_misc_info["build_super_partition"] = "false" # super split
1328 with open(vendor_misc_info_path, "w") as output:
1329 for key in sorted(vendor_misc_info):
1330 output.write("{}={}\n".format(key, vendor_misc_info[key]))
1331
Po Hu0663ae42021-09-27 12:59:06 +08001332 # Disable system partition by a placeholder of IMAGES/system.img,
1333 # instead of removing SYSTEM folder.
1334 # Because SYSTEM/build.prop is still needed for:
1335 # add_img_to_target_files.CreateImage ->
1336 # common.BuildInfo ->
1337 # common.BuildInfo.CalculateFingerprint
1338 vendor_images_path = os.path.join(vendor_tempdir, "IMAGES")
1339 if not os.path.exists(vendor_images_path):
1340 os.makedirs(vendor_images_path)
1341 with open(os.path.join(vendor_images_path, "system.img"), "w") as output:
1342 pass
1343
Daniel Norman78554ea2021-09-14 10:29:38 -07001344 # Disable care_map.pb as not all ab_partitions are available when
1345 # vendor otatools regenerates vendor images.
Po Hu0663ae42021-09-27 12:59:06 +08001346 if os.path.exists(os.path.join(vendor_tempdir, "META/ab_partitions.txt")):
1347 os.remove(os.path.join(vendor_tempdir, "META/ab_partitions.txt"))
1348 # Disable RADIO images
1349 if os.path.exists(os.path.join(vendor_tempdir, "META/pack_radioimages.txt")):
1350 os.remove(os.path.join(vendor_tempdir, "META/pack_radioimages.txt"))
Daniel Norman78554ea2021-09-14 10:29:38 -07001351
1352 # Build vendor images using vendor otatools.
Iavor-Valentin Iftime63cde0f2022-03-04 16:02:44 +00001353 # Accept either a zip file or extracted directory.
1354 if os.path.isfile(OPTIONS.vendor_otatools):
1355 vendor_otatools_dir = common.MakeTempDir(prefix="vendor_otatools_")
1356 common.UnzipToDir(OPTIONS.vendor_otatools, vendor_otatools_dir)
1357 else:
1358 vendor_otatools_dir = OPTIONS.vendor_otatools
Daniel Norman78554ea2021-09-14 10:29:38 -07001359 cmd = [
1360 os.path.join(vendor_otatools_dir, "bin", "add_img_to_target_files"),
1361 "--is_signing",
Po Hu0663ae42021-09-27 12:59:06 +08001362 "--add_missing",
Daniel Norman78554ea2021-09-14 10:29:38 -07001363 "--verbose",
1364 vendor_tempdir,
1365 ]
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001366 if OPTIONS.rebuild_recovery:
1367 cmd.insert(4, "--rebuild_recovery")
1368
Daniel Norman78554ea2021-09-14 10:29:38 -07001369 common.RunAndCheckOutput(cmd, verbose=True)
1370
1371 logger.info("Writing vendor partitions to output archive.")
1372 with zipfile.ZipFile(
1373 output_zip_path, "a", compression=zipfile.ZIP_DEFLATED,
1374 allowZip64=True) as output_zip:
1375 for p in OPTIONS.vendor_partitions:
Iavor-Valentin Iftime880e4432022-03-17 14:02:27 +00001376 img_file_path = "IMAGES/{}.img".format(p)
1377 map_file_path = "IMAGES/{}.map".format(p)
1378 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, img_file_path), img_file_path)
jiangxu5b67b0d52022-06-03 14:46:56 +08001379 if os.path.exists(os.path.join(vendor_tempdir, map_file_path)):
1380 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, map_file_path), map_file_path)
Iavor-Valentin Iftime40adb172022-04-19 18:17:56 +00001381 # copy recovery.img, boot.img, recovery patch & install.sh
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001382 if OPTIONS.rebuild_recovery:
Iavor-Valentin Iftime40adb172022-04-19 18:17:56 +00001383 recovery_img = "IMAGES/recovery.img"
1384 boot_img = "IMAGES/boot.img"
1385 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, recovery_img), recovery_img)
1386 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, boot_img), boot_img)
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001387 recovery_patch_path = "VENDOR/recovery-from-boot.p"
1388 recovery_sh_path = "VENDOR/bin/install-recovery.sh"
1389 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, recovery_patch_path), recovery_patch_path)
1390 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, recovery_sh_path), recovery_sh_path)
Daniel Norman78554ea2021-09-14 10:29:38 -07001391
1392
Doug Zongkereef39442009-04-02 12:14:19 -07001393def main(argv):
1394
Doug Zongker831840e2011-09-22 10:28:04 -07001395 key_mapping_options = []
1396
Doug Zongkereef39442009-04-02 12:14:19 -07001397 def option_handler(o, a):
Doug Zongker05d3dea2009-06-22 11:32:31 -07001398 if o in ("-e", "--extra_apks"):
Doug Zongkereef39442009-04-02 12:14:19 -07001399 names, key = a.split("=")
1400 names = names.split(",")
1401 for n in names:
1402 OPTIONS.extra_apks[n] = key
Tao Baoaa7e9932019-03-15 09:37:01 -07001403 elif o == "--extra_apex_payload_key":
Kelvin Zhang085b6f32022-07-25 16:12:30 -07001404 apex_names, key = a.split("=")
Kelvin Zhang87e45272022-07-27 11:14:12 -07001405 for name in apex_names.split(","):
Kelvin Zhang085b6f32022-07-25 16:12:30 -07001406 OPTIONS.extra_apex_payload_keys[name] = key
Tao Bao93c2a012018-06-19 12:19:35 -07001407 elif o == "--skip_apks_with_path_prefix":
Tianjiea85bdf02020-07-29 11:56:19 -07001408 # Check the prefix, which must be in all upper case.
Tao Bao93c2a012018-06-19 12:19:35 -07001409 prefix = a.split('/')[0]
1410 if not prefix or prefix != prefix.upper():
1411 raise ValueError("Invalid path prefix '%s'" % (a,))
1412 OPTIONS.skip_apks_with_path_prefix.add(a)
Doug Zongkereef39442009-04-02 12:14:19 -07001413 elif o in ("-d", "--default_key_mappings"):
Doug Zongker831840e2011-09-22 10:28:04 -07001414 key_mapping_options.append((None, a))
Doug Zongkereef39442009-04-02 12:14:19 -07001415 elif o in ("-k", "--key_mapping"):
Doug Zongker831840e2011-09-22 10:28:04 -07001416 key_mapping_options.append(a.split("=", 1))
Doug Zongker8e931bf2009-04-06 15:21:45 -07001417 elif o in ("-o", "--replace_ota_keys"):
1418 OPTIONS.replace_ota_keys = True
Doug Zongkerae877012009-04-21 10:04:51 -07001419 elif o in ("-t", "--tag_changes"):
1420 new = []
1421 for i in a.split(","):
1422 i = i.strip()
1423 if not i or i[0] not in "-+":
1424 raise ValueError("Bad tag change '%s'" % (i,))
1425 new.append(i[0] + i[1:].strip())
1426 OPTIONS.tag_changes = tuple(new)
Geremy Condraf19b3652014-07-29 17:54:54 -07001427 elif o == "--replace_verity_public_key":
1428 OPTIONS.replace_verity_public_key = (True, a)
1429 elif o == "--replace_verity_private_key":
1430 OPTIONS.replace_verity_private_key = (True, a)
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001431 elif o == "--replace_verity_keyid":
1432 OPTIONS.replace_verity_keyid = (True, a)
Bowgo Tsai2fe786a2020-02-21 17:48:18 +08001433 elif o == "--remove_avb_public_keys":
1434 OPTIONS.remove_avb_public_keys = a.split(",")
Tao Bao639118f2017-06-19 15:48:02 -07001435 elif o == "--avb_vbmeta_key":
1436 OPTIONS.avb_keys['vbmeta'] = a
1437 elif o == "--avb_vbmeta_algorithm":
1438 OPTIONS.avb_algorithms['vbmeta'] = a
1439 elif o == "--avb_vbmeta_extra_args":
1440 OPTIONS.avb_extra_args['vbmeta'] = a
1441 elif o == "--avb_boot_key":
1442 OPTIONS.avb_keys['boot'] = a
1443 elif o == "--avb_boot_algorithm":
1444 OPTIONS.avb_algorithms['boot'] = a
1445 elif o == "--avb_boot_extra_args":
1446 OPTIONS.avb_extra_args['boot'] = a
1447 elif o == "--avb_dtbo_key":
1448 OPTIONS.avb_keys['dtbo'] = a
1449 elif o == "--avb_dtbo_algorithm":
1450 OPTIONS.avb_algorithms['dtbo'] = a
1451 elif o == "--avb_dtbo_extra_args":
1452 OPTIONS.avb_extra_args['dtbo'] = a
1453 elif o == "--avb_system_key":
1454 OPTIONS.avb_keys['system'] = a
1455 elif o == "--avb_system_algorithm":
1456 OPTIONS.avb_algorithms['system'] = a
1457 elif o == "--avb_system_extra_args":
1458 OPTIONS.avb_extra_args['system'] = a
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001459 elif o == "--avb_system_other_key":
1460 OPTIONS.avb_keys['system_other'] = a
1461 elif o == "--avb_system_other_algorithm":
1462 OPTIONS.avb_algorithms['system_other'] = a
1463 elif o == "--avb_system_other_extra_args":
1464 OPTIONS.avb_extra_args['system_other'] = a
Tao Bao639118f2017-06-19 15:48:02 -07001465 elif o == "--avb_vendor_key":
1466 OPTIONS.avb_keys['vendor'] = a
1467 elif o == "--avb_vendor_algorithm":
1468 OPTIONS.avb_algorithms['vendor'] = a
1469 elif o == "--avb_vendor_extra_args":
1470 OPTIONS.avb_extra_args['vendor'] = a
Tao Baod6085d62019-05-06 12:55:42 -07001471 elif o == "--avb_vbmeta_system_key":
1472 OPTIONS.avb_keys['vbmeta_system'] = a
1473 elif o == "--avb_vbmeta_system_algorithm":
1474 OPTIONS.avb_algorithms['vbmeta_system'] = a
1475 elif o == "--avb_vbmeta_system_extra_args":
1476 OPTIONS.avb_extra_args['vbmeta_system'] = a
1477 elif o == "--avb_vbmeta_vendor_key":
1478 OPTIONS.avb_keys['vbmeta_vendor'] = a
1479 elif o == "--avb_vbmeta_vendor_algorithm":
1480 OPTIONS.avb_algorithms['vbmeta_vendor'] = a
1481 elif o == "--avb_vbmeta_vendor_extra_args":
1482 OPTIONS.avb_extra_args['vbmeta_vendor'] = a
Tao Baoaa7e9932019-03-15 09:37:01 -07001483 elif o == "--avb_apex_extra_args":
1484 OPTIONS.avb_extra_args['apex'] = a
Hongguang Chenf23364d2020-04-27 18:36:36 -07001485 elif o == "--avb_extra_custom_image_key":
1486 partition, key = a.split("=")
1487 OPTIONS.avb_keys[partition] = key
1488 elif o == "--avb_extra_custom_image_algorithm":
1489 partition, algorithm = a.split("=")
1490 OPTIONS.avb_algorithms[partition] = algorithm
1491 elif o == "--avb_extra_custom_image_extra_args":
Hongguang Chen883eecb2020-05-23 22:20:19 -07001492 # Setting the maxsplit parameter to one, which will return a list with
1493 # two elements. e.g., the second '=' should not be splitted for
1494 # 'oem=--signing_helper_with_files=/tmp/avbsigner.sh'.
1495 partition, extra_args = a.split("=", 1)
Hongguang Chenf23364d2020-04-27 18:36:36 -07001496 OPTIONS.avb_extra_args[partition] = extra_args
Bowgo Tsai27c39b02021-03-12 21:40:32 +08001497 elif o == "--gki_signing_key":
1498 OPTIONS.gki_signing_key = a
1499 elif o == "--gki_signing_algorithm":
1500 OPTIONS.gki_signing_algorithm = a
1501 elif o == "--gki_signing_extra_args":
1502 OPTIONS.gki_signing_extra_args = a
Daniel Norman78554ea2021-09-14 10:29:38 -07001503 elif o == "--vendor_otatools":
1504 OPTIONS.vendor_otatools = a
1505 elif o == "--vendor_partitions":
1506 OPTIONS.vendor_partitions = set(a.split(","))
Bowgo Tsai2a781692021-10-13 17:39:33 +08001507 elif o == "--allow_gsi_debug_sepolicy":
1508 OPTIONS.allow_gsi_debug_sepolicy = True
Kelvin Zhange50bb512022-08-01 15:58:51 -07001509 elif o == "--override_apk_keys":
1510 OPTIONS.override_apk_keys = a
1511 elif o == "--override_apex_keys":
1512 OPTIONS.override_apex_keys = a
Doug Zongkereef39442009-04-02 12:14:19 -07001513 else:
1514 return False
1515 return True
1516
Tao Bao639118f2017-06-19 15:48:02 -07001517 args = common.ParseOptions(
1518 argv, __doc__,
1519 extra_opts="e:d:k:ot:",
1520 extra_long_opts=[
Tao Bao0c28d2d2017-12-24 10:37:38 -08001521 "extra_apks=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001522 "extra_apex_payload_key=",
Tao Bao93c2a012018-06-19 12:19:35 -07001523 "skip_apks_with_path_prefix=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001524 "default_key_mappings=",
1525 "key_mapping=",
1526 "replace_ota_keys",
1527 "tag_changes=",
1528 "replace_verity_public_key=",
1529 "replace_verity_private_key=",
1530 "replace_verity_keyid=",
Bowgo Tsai2fe786a2020-02-21 17:48:18 +08001531 "remove_avb_public_keys=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001532 "avb_apex_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001533 "avb_vbmeta_algorithm=",
1534 "avb_vbmeta_key=",
1535 "avb_vbmeta_extra_args=",
1536 "avb_boot_algorithm=",
1537 "avb_boot_key=",
1538 "avb_boot_extra_args=",
1539 "avb_dtbo_algorithm=",
1540 "avb_dtbo_key=",
1541 "avb_dtbo_extra_args=",
1542 "avb_system_algorithm=",
1543 "avb_system_key=",
1544 "avb_system_extra_args=",
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001545 "avb_system_other_algorithm=",
1546 "avb_system_other_key=",
1547 "avb_system_other_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001548 "avb_vendor_algorithm=",
1549 "avb_vendor_key=",
1550 "avb_vendor_extra_args=",
Tao Baod6085d62019-05-06 12:55:42 -07001551 "avb_vbmeta_system_algorithm=",
1552 "avb_vbmeta_system_key=",
1553 "avb_vbmeta_system_extra_args=",
1554 "avb_vbmeta_vendor_algorithm=",
1555 "avb_vbmeta_vendor_key=",
1556 "avb_vbmeta_vendor_extra_args=",
Hongguang Chenf23364d2020-04-27 18:36:36 -07001557 "avb_extra_custom_image_key=",
1558 "avb_extra_custom_image_algorithm=",
1559 "avb_extra_custom_image_extra_args=",
Bowgo Tsai27c39b02021-03-12 21:40:32 +08001560 "gki_signing_key=",
1561 "gki_signing_algorithm=",
1562 "gki_signing_extra_args=",
Daniel Norman78554ea2021-09-14 10:29:38 -07001563 "vendor_partitions=",
1564 "vendor_otatools=",
Bowgo Tsai2a781692021-10-13 17:39:33 +08001565 "allow_gsi_debug_sepolicy",
Kelvin Zhange50bb512022-08-01 15:58:51 -07001566 "override_apk_keys=",
1567 "override_apex_keys=",
Tao Bao639118f2017-06-19 15:48:02 -07001568 ],
1569 extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001570
1571 if len(args) != 2:
1572 common.Usage(__doc__)
1573 sys.exit(1)
1574
Tao Baobadceb22019-03-15 09:33:43 -07001575 common.InitLogging()
1576
Kelvin Zhang928c2342020-09-22 16:15:57 -04001577 input_zip = zipfile.ZipFile(args[0], "r", allowZip64=True)
Tao Bao2b8f4892017-06-13 12:54:58 -07001578 output_zip = zipfile.ZipFile(args[1], "w",
1579 compression=zipfile.ZIP_DEFLATED,
1580 allowZip64=True)
Doug Zongkereef39442009-04-02 12:14:19 -07001581
Doug Zongker831840e2011-09-22 10:28:04 -07001582 misc_info = common.LoadInfoDict(input_zip)
1583
1584 BuildKeyMap(misc_info, key_mapping_options)
1585
Tao Baoaa7e9932019-03-15 09:37:01 -07001586 apk_keys_info, compressed_extension = common.ReadApkCerts(input_zip)
1587 apk_keys = GetApkCerts(apk_keys_info)
Doug Zongkereb338ef2009-05-20 16:50:49 -07001588
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001589 apex_keys_info = ReadApexKeysInfo(input_zip)
Tao Baoaa7e9932019-03-15 09:37:01 -07001590 apex_keys = GetApexKeys(apex_keys_info, apk_keys)
1591
Tianjie Xu88a759d2020-01-23 10:47:54 -08001592 # TODO(xunchang) check for the apks inside the apex files, and abort early if
1593 # the keys are not available.
Tao Baoaa7e9932019-03-15 09:37:01 -07001594 CheckApkAndApexKeysAvailable(
1595 input_zip,
1596 set(apk_keys.keys()) | set(apex_keys.keys()),
Tao Baoe1343992019-03-19 12:24:03 -07001597 compressed_extension,
1598 apex_keys)
Tao Baoaa7e9932019-03-15 09:37:01 -07001599
1600 key_passwords = common.GetKeyPasswords(
1601 set(apk_keys.values()) | set(itertools.chain(*apex_keys.values())))
Tao Bao9aa4b9b2016-09-29 17:53:56 -07001602 platform_api_level, _ = GetApiLevelAndCodename(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001603 codename_to_api_level_map = GetCodenameToApiLevelMap(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001604
Doug Zongker412c02f2014-02-13 10:58:24 -08001605 ProcessTargetFiles(input_zip, output_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -07001606 apk_keys, apex_keys, key_passwords,
1607 platform_api_level, codename_to_api_level_map,
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001608 compressed_extension)
Doug Zongker8e931bf2009-04-06 15:21:45 -07001609
Tao Bao2ed665a2015-04-01 11:21:55 -07001610 common.ZipClose(input_zip)
1611 common.ZipClose(output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001612
Daniel Norman78554ea2021-09-14 10:29:38 -07001613 if OPTIONS.vendor_partitions and OPTIONS.vendor_otatools:
1614 BuildVendorPartitions(args[1])
1615
Tianjie Xub48589a2016-08-03 19:21:52 -07001616 # Skip building userdata.img and cache.img when signing the target files.
Daniel Norman78554ea2021-09-14 10:29:38 -07001617 new_args = ["--is_signing", "--add_missing", "--verbose"]
Tianjie Xu616fbeb2017-05-23 14:51:02 -07001618 # add_img_to_target_files builds the system image from scratch, so the
1619 # recovery patch is guaranteed to be regenerated there.
1620 if OPTIONS.rebuild_recovery:
1621 new_args.append("--rebuild_recovery")
1622 new_args.append(args[1])
Tianjie Xub48589a2016-08-03 19:21:52 -07001623 add_img_to_target_files.main(new_args)
Doug Zongker3c84f562014-07-31 11:06:30 -07001624
Tao Bao0c28d2d2017-12-24 10:37:38 -08001625 print("done.")
Doug Zongkereef39442009-04-02 12:14:19 -07001626
1627
1628if __name__ == '__main__':
1629 try:
1630 main(sys.argv[1:])
Tao Bao639118f2017-06-19 15:48:02 -07001631 finally:
1632 common.Cleanup()