blob: 78fc8866bf51aae9b5171192596a29a4627dc3f7 [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
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.
Doug Zongkereef39442009-04-02 12:14:19 -0700144"""
145
Tao Bao0c28d2d2017-12-24 10:37:38 -0800146from __future__ import print_function
Doug Zongkereef39442009-04-02 12:14:19 -0700147
Robert Craig817c5742013-04-19 10:59:22 -0400148import base64
Doug Zongker8e931bf2009-04-06 15:21:45 -0700149import copy
Robert Craig817c5742013-04-19 10:59:22 -0400150import errno
Narayan Kamatha07bf042017-08-14 14:49:21 +0100151import gzip
Tao Baobb733882019-07-24 23:31:19 -0700152import io
Tao Baoaa7e9932019-03-15 09:37:01 -0700153import itertools
Tao Baobadceb22019-03-15 09:33:43 -0700154import logging
Doug Zongkereef39442009-04-02 12:14:19 -0700155import os
156import re
Narayan Kamatha07bf042017-08-14 14:49:21 +0100157import shutil
Tao Bao9fdd00f2017-07-12 11:57:05 -0700158import stat
Doug Zongkereef39442009-04-02 12:14:19 -0700159import subprocess
Tao Bao0c28d2d2017-12-24 10:37:38 -0800160import sys
Doug Zongkereef39442009-04-02 12:14:19 -0700161import tempfile
162import zipfile
Tao Bao66472632017-12-04 17:16:36 -0800163from xml.etree import ElementTree
Doug Zongkereef39442009-04-02 12:14:19 -0700164
Doug Zongker3c84f562014-07-31 11:06:30 -0700165import add_img_to_target_files
Tao Baoaa7e9932019-03-15 09:37:01 -0700166import apex_utils
Doug Zongkereef39442009-04-02 12:14:19 -0700167import common
168
Tao Bao0c28d2d2017-12-24 10:37:38 -0800169
170if sys.hexversion < 0x02070000:
171 print("Python 2.7 or newer is required.", file=sys.stderr)
172 sys.exit(1)
173
174
Tao Baobadceb22019-03-15 09:33:43 -0700175logger = logging.getLogger(__name__)
176
Doug Zongkereef39442009-04-02 12:14:19 -0700177OPTIONS = common.OPTIONS
178
179OPTIONS.extra_apks = {}
Tao Baoaa7e9932019-03-15 09:37:01 -0700180OPTIONS.extra_apex_payload_keys = {}
Tao Bao93c2a012018-06-19 12:19:35 -0700181OPTIONS.skip_apks_with_path_prefix = set()
Doug Zongkereef39442009-04-02 12:14:19 -0700182OPTIONS.key_map = {}
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700183OPTIONS.rebuild_recovery = False
Doug Zongker8e931bf2009-04-06 15:21:45 -0700184OPTIONS.replace_ota_keys = False
Geremy Condraf19b3652014-07-29 17:54:54 -0700185OPTIONS.replace_verity_public_key = False
186OPTIONS.replace_verity_private_key = False
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700187OPTIONS.replace_verity_keyid = False
Bowgo Tsai2fe786a2020-02-21 17:48:18 +0800188OPTIONS.remove_avb_public_keys = None
Doug Zongker831840e2011-09-22 10:28:04 -0700189OPTIONS.tag_changes = ("-test-keys", "-dev-keys", "+release-keys")
Tao Bao639118f2017-06-19 15:48:02 -0700190OPTIONS.avb_keys = {}
191OPTIONS.avb_algorithms = {}
192OPTIONS.avb_extra_args = {}
Bowgo Tsai27c39b02021-03-12 21:40:32 +0800193OPTIONS.gki_signing_key = None
194OPTIONS.gki_signing_algorithm = None
195OPTIONS.gki_signing_extra_args = None
Tianjie Xu88a759d2020-01-23 10:47:54 -0800196OPTIONS.android_jar_path = None
Daniel Norman78554ea2021-09-14 10:29:38 -0700197OPTIONS.vendor_partitions = set()
198OPTIONS.vendor_otatools = None
Bowgo Tsai2a781692021-10-13 17:39:33 +0800199OPTIONS.allow_gsi_debug_sepolicy = False
Doug Zongkereef39442009-04-02 12:14:19 -0700200
Tao Bao0c28d2d2017-12-24 10:37:38 -0800201
Tao Bao19b02fe2019-10-09 00:04:28 -0700202AVB_FOOTER_ARGS_BY_PARTITION = {
Tianjiebf0b8a82021-03-03 17:31:04 -0800203 'boot': 'avb_boot_add_hash_footer_args',
Devin Mooreafdd7c72021-12-13 22:04:08 +0000204 'init_boot': 'avb_init_boot_add_hash_footer_args',
Tianjiebf0b8a82021-03-03 17:31:04 -0800205 'dtbo': 'avb_dtbo_add_hash_footer_args',
206 'product': 'avb_product_add_hashtree_footer_args',
207 'recovery': 'avb_recovery_add_hash_footer_args',
208 'system': 'avb_system_add_hashtree_footer_args',
Ramji Jiyani13a41372022-01-27 07:05:08 +0000209 'system_dlkm': "avb_system_dlkm_add_hashtree_footer_args",
Tianjiebf0b8a82021-03-03 17:31:04 -0800210 'system_ext': 'avb_system_ext_add_hashtree_footer_args',
211 'system_other': 'avb_system_other_add_hashtree_footer_args',
212 'odm': 'avb_odm_add_hashtree_footer_args',
213 'odm_dlkm': 'avb_odm_dlkm_add_hashtree_footer_args',
214 'pvmfw': 'avb_pvmfw_add_hash_footer_args',
215 'vendor': 'avb_vendor_add_hashtree_footer_args',
216 'vendor_boot': 'avb_vendor_boot_add_hash_footer_args',
Lucas Wei03230252022-04-18 16:00:40 +0800217 'vendor_kernel_boot': 'avb_vendor_kernel_boot_add_hash_footer_args',
Tianjiebf0b8a82021-03-03 17:31:04 -0800218 'vendor_dlkm': "avb_vendor_dlkm_add_hashtree_footer_args",
219 'vbmeta': 'avb_vbmeta_args',
220 'vbmeta_system': 'avb_vbmeta_system_args',
221 'vbmeta_vendor': 'avb_vbmeta_vendor_args',
Tao Bao19b02fe2019-10-09 00:04:28 -0700222}
223
224
Tianjiebf0b8a82021-03-03 17:31:04 -0800225# Check that AVB_FOOTER_ARGS_BY_PARTITION is in sync with AVB_PARTITIONS.
226for partition in common.AVB_PARTITIONS:
227 if partition not in AVB_FOOTER_ARGS_BY_PARTITION:
228 raise RuntimeError("Missing {} in AVB_FOOTER_ARGS".format(partition))
229
Daniel Norman78554ea2021-09-14 10:29:38 -0700230# Partitions that can be regenerated after signing using a separate
231# vendor otatools package.
232ALLOWED_VENDOR_PARTITIONS = set(["vendor", "odm"])
233
Tianjiebf0b8a82021-03-03 17:31:04 -0800234
Tianjie4d48d502021-06-11 17:03:43 -0700235def IsApexFile(filename):
236 return filename.endswith(".apex") or filename.endswith(".capex")
237
238
239def GetApexFilename(filename):
240 name = os.path.basename(filename)
241 # Replace the suffix for compressed apex
242 if name.endswith(".capex"):
243 return name.replace(".capex", ".apex")
244 return name
245
246
Narayan Kamatha07bf042017-08-14 14:49:21 +0100247def GetApkCerts(certmap):
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800248 # apply the key remapping to the contents of the file
Tao Baoa3705452019-06-24 15:33:41 -0700249 for apk, cert in certmap.items():
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800250 certmap[apk] = OPTIONS.key_map.get(cert, cert)
251
252 # apply all the -e options, overriding anything in the file
Tao Baoa3705452019-06-24 15:33:41 -0700253 for apk, cert in OPTIONS.extra_apks.items():
Doug Zongkerdecf9952009-12-15 17:27:49 -0800254 if not cert:
255 cert = "PRESIGNED"
Doug Zongkerad88c7c2009-04-14 12:34:27 -0700256 certmap[apk] = OPTIONS.key_map.get(cert, cert)
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800257
Doug Zongkereef39442009-04-02 12:14:19 -0700258 return certmap
259
260
Tao Baoaa7e9932019-03-15 09:37:01 -0700261def GetApexKeys(keys_info, key_map):
262 """Gets APEX payload and container signing keys by applying the mapping rules.
263
Tao Baoe1343992019-03-19 12:24:03 -0700264 Presigned payload / container keys will be set accordingly.
Tao Baoaa7e9932019-03-15 09:37:01 -0700265
266 Args:
267 keys_info: A dict that maps from APEX filenames to a tuple of (payload_key,
Jooyung Han8caba5e2021-10-27 03:58:09 +0900268 container_key, sign_tool).
Tao Baoaa7e9932019-03-15 09:37:01 -0700269 key_map: A dict that overrides the keys, specified via command-line input.
270
271 Returns:
272 A dict that contains the updated APEX key mapping, which should be used for
273 the current signing.
Tao Baof98fa102019-04-24 14:51:25 -0700274
275 Raises:
276 AssertionError: On invalid container / payload key overrides.
Tao Baoaa7e9932019-03-15 09:37:01 -0700277 """
278 # Apply all the --extra_apex_payload_key options to override the payload
279 # signing keys in the given keys_info.
280 for apex, key in OPTIONS.extra_apex_payload_keys.items():
Tao Baoe1343992019-03-19 12:24:03 -0700281 if not key:
282 key = 'PRESIGNED'
Tao Bao34223092019-07-11 11:52:52 -0700283 if apex not in keys_info:
284 logger.warning('Failed to find %s in target_files; Ignored', apex)
285 continue
Jooyung Han8caba5e2021-10-27 03:58:09 +0900286 keys_info[apex] = (key, keys_info[apex][1], keys_info[apex][2])
Tao Baoaa7e9932019-03-15 09:37:01 -0700287
288 # Apply the key remapping to container keys.
Jooyung Han8caba5e2021-10-27 03:58:09 +0900289 for apex, (payload_key, container_key, sign_tool) in keys_info.items():
290 keys_info[apex] = (payload_key, key_map.get(container_key, container_key), sign_tool)
Tao Baoaa7e9932019-03-15 09:37:01 -0700291
292 # Apply all the --extra_apks options to override the container keys.
293 for apex, key in OPTIONS.extra_apks.items():
294 # Skip non-APEX containers.
295 if apex not in keys_info:
296 continue
Tao Baoe1343992019-03-19 12:24:03 -0700297 if not key:
298 key = 'PRESIGNED'
Jooyung Han8caba5e2021-10-27 03:58:09 +0900299 keys_info[apex] = (keys_info[apex][0], key_map.get(key, key), keys_info[apex][2])
Tao Baoaa7e9932019-03-15 09:37:01 -0700300
Tao Baof98fa102019-04-24 14:51:25 -0700301 # A PRESIGNED container entails a PRESIGNED payload. Apply this to all the
302 # APEX key pairs. However, a PRESIGNED container with non-PRESIGNED payload
303 # (overridden via commandline) indicates a config error, which should not be
304 # allowed.
Jooyung Han8caba5e2021-10-27 03:58:09 +0900305 for apex, (payload_key, container_key, sign_tool) in keys_info.items():
Tao Baof98fa102019-04-24 14:51:25 -0700306 if container_key != 'PRESIGNED':
307 continue
308 if apex in OPTIONS.extra_apex_payload_keys:
309 payload_override = OPTIONS.extra_apex_payload_keys[apex]
310 assert payload_override == '', \
311 ("Invalid APEX key overrides: {} has PRESIGNED container but "
312 "non-PRESIGNED payload key {}").format(apex, payload_override)
313 if payload_key != 'PRESIGNED':
314 print(
315 "Setting {} payload as PRESIGNED due to PRESIGNED container".format(
316 apex))
Jooyung Han8caba5e2021-10-27 03:58:09 +0900317 keys_info[apex] = ('PRESIGNED', 'PRESIGNED', None)
Tao Baof98fa102019-04-24 14:51:25 -0700318
Tao Baoaa7e9932019-03-15 09:37:01 -0700319 return keys_info
320
321
Tao Bao93c2a012018-06-19 12:19:35 -0700322def GetApkFileInfo(filename, compressed_extension, skipped_prefixes):
Tao Bao11f955c2018-06-19 12:19:35 -0700323 """Returns the APK info based on the given filename.
324
325 Checks if the given filename (with path) looks like an APK file, by taking the
Tao Bao93c2a012018-06-19 12:19:35 -0700326 compressed extension into consideration. If it appears to be an APK file,
327 further checks if the APK file should be skipped when signing, based on the
328 given path prefixes.
Tao Bao11f955c2018-06-19 12:19:35 -0700329
330 Args:
331 filename: Path to the file.
332 compressed_extension: The extension string of compressed APKs (e.g. ".gz"),
333 or None if there's no compressed APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700334 skipped_prefixes: A set/list/tuple of the path prefixes to be skipped.
Tao Bao11f955c2018-06-19 12:19:35 -0700335
336 Returns:
Tao Bao93c2a012018-06-19 12:19:35 -0700337 (is_apk, is_compressed, should_be_skipped): is_apk indicates whether the
338 given filename is an APK file. is_compressed indicates whether the APK file
339 is compressed (only meaningful when is_apk is True). should_be_skipped
340 indicates whether the filename matches any of the given prefixes to be
341 skipped.
Tao Bao11f955c2018-06-19 12:19:35 -0700342
343 Raises:
Tao Bao93c2a012018-06-19 12:19:35 -0700344 AssertionError: On invalid compressed_extension or skipped_prefixes inputs.
Tao Bao11f955c2018-06-19 12:19:35 -0700345 """
346 assert compressed_extension is None or compressed_extension.startswith('.'), \
347 "Invalid compressed_extension arg: '{}'".format(compressed_extension)
348
Tao Bao93c2a012018-06-19 12:19:35 -0700349 # skipped_prefixes should be one of set/list/tuple types. Other types such as
350 # str shouldn't be accepted.
Tao Baobadceb22019-03-15 09:33:43 -0700351 assert isinstance(skipped_prefixes, (set, list, tuple)), \
352 "Invalid skipped_prefixes input type: {}".format(type(skipped_prefixes))
Tao Bao93c2a012018-06-19 12:19:35 -0700353
Tao Bao11f955c2018-06-19 12:19:35 -0700354 compressed_apk_extension = (
355 ".apk" + compressed_extension if compressed_extension else None)
356 is_apk = (filename.endswith(".apk") or
357 (compressed_apk_extension and
358 filename.endswith(compressed_apk_extension)))
359 if not is_apk:
Tao Bao93c2a012018-06-19 12:19:35 -0700360 return (False, False, False)
Tao Bao11f955c2018-06-19 12:19:35 -0700361
362 is_compressed = (compressed_apk_extension and
363 filename.endswith(compressed_apk_extension))
Tao Bao93c2a012018-06-19 12:19:35 -0700364 should_be_skipped = filename.startswith(tuple(skipped_prefixes))
365 return (True, is_compressed, should_be_skipped)
Tao Bao11f955c2018-06-19 12:19:35 -0700366
367
Tao Baoaa7e9932019-03-15 09:37:01 -0700368def CheckApkAndApexKeysAvailable(input_tf_zip, known_keys,
Tao Baoe1343992019-03-19 12:24:03 -0700369 compressed_extension, apex_keys):
Tao Baoaa7e9932019-03-15 09:37:01 -0700370 """Checks that all the APKs and APEXes have keys specified.
Tao Bao11f955c2018-06-19 12:19:35 -0700371
372 Args:
373 input_tf_zip: An open target_files zip file.
Tao Baoaa7e9932019-03-15 09:37:01 -0700374 known_keys: A set of APKs and APEXes that have known signing keys.
Tao Bao11f955c2018-06-19 12:19:35 -0700375 compressed_extension: The extension string of compressed APKs, such as
Tao Baoaa7e9932019-03-15 09:37:01 -0700376 '.gz', or None if there's no compressed APKs.
Tao Baoe1343992019-03-19 12:24:03 -0700377 apex_keys: A dict that contains the key mapping from APEX name to
Jooyung Han8caba5e2021-10-27 03:58:09 +0900378 (payload_key, container_key, sign_tool).
Tao Bao11f955c2018-06-19 12:19:35 -0700379
380 Raises:
Tao Baoaa7e9932019-03-15 09:37:01 -0700381 AssertionError: On finding unknown APKs and APEXes.
Tao Bao11f955c2018-06-19 12:19:35 -0700382 """
Tao Baoaa7e9932019-03-15 09:37:01 -0700383 unknown_files = []
Doug Zongkereb338ef2009-05-20 16:50:49 -0700384 for info in input_tf_zip.infolist():
Tianjie5bd03952021-02-18 23:02:36 -0800385 # Handle APEXes on all partitions
Tianjie4d48d502021-06-11 17:03:43 -0700386 if IsApexFile(info.filename):
387 name = GetApexFilename(info.filename)
Tao Baoaa7e9932019-03-15 09:37:01 -0700388 if name not in known_keys:
389 unknown_files.append(name)
390 continue
391
392 # And APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700393 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
394 info.filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
395 if not is_apk or should_be_skipped:
Tao Bao11f955c2018-06-19 12:19:35 -0700396 continue
Tao Baoaa7e9932019-03-15 09:37:01 -0700397
Tao Bao11f955c2018-06-19 12:19:35 -0700398 name = os.path.basename(info.filename)
399 if is_compressed:
400 name = name[:-len(compressed_extension)]
Tao Baoaa7e9932019-03-15 09:37:01 -0700401 if name not in known_keys:
402 unknown_files.append(name)
Tao Bao11f955c2018-06-19 12:19:35 -0700403
Tao Baoaa7e9932019-03-15 09:37:01 -0700404 assert not unknown_files, \
Tao Bao11f955c2018-06-19 12:19:35 -0700405 ("No key specified for:\n {}\n"
406 "Use '-e <apkname>=' to specify a key (which may be an empty string to "
Tao Baoaa7e9932019-03-15 09:37:01 -0700407 "not sign this apk).".format("\n ".join(unknown_files)))
Doug Zongkereb338ef2009-05-20 16:50:49 -0700408
Tao Baoe1343992019-03-19 12:24:03 -0700409 # For all the APEXes, double check that we won't have an APEX that has only
Tao Baof98fa102019-04-24 14:51:25 -0700410 # one of the payload / container keys set. Note that non-PRESIGNED container
411 # with PRESIGNED payload could be allowed but currently unsupported. It would
412 # require changing SignApex implementation.
Tao Baoe1343992019-03-19 12:24:03 -0700413 if not apex_keys:
414 return
415
416 invalid_apexes = []
417 for info in input_tf_zip.infolist():
Tianjie4d48d502021-06-11 17:03:43 -0700418 if not IsApexFile(info.filename):
Tao Baoe1343992019-03-19 12:24:03 -0700419 continue
420
Tianjie4d48d502021-06-11 17:03:43 -0700421 name = GetApexFilename(info.filename)
422
Jooyung Han8caba5e2021-10-27 03:58:09 +0900423 (payload_key, container_key, _) = apex_keys[name]
Tao Baoe1343992019-03-19 12:24:03 -0700424 if ((payload_key in common.SPECIAL_CERT_STRINGS and
425 container_key not in common.SPECIAL_CERT_STRINGS) or
426 (payload_key not in common.SPECIAL_CERT_STRINGS and
427 container_key in common.SPECIAL_CERT_STRINGS)):
428 invalid_apexes.append(
429 "{}: payload_key {}, container_key {}".format(
430 name, payload_key, container_key))
431
432 assert not invalid_apexes, \
433 "Invalid APEX keys specified:\n {}\n".format(
434 "\n ".join(invalid_apexes))
435
Doug Zongkereb338ef2009-05-20 16:50:49 -0700436
Narayan Kamatha07bf042017-08-14 14:49:21 +0100437def SignApk(data, keyname, pw, platform_api_level, codename_to_api_level_map,
Oleg Aravin8046cb02020-06-02 16:02:38 -0700438 is_compressed, apk_name):
439 unsigned = tempfile.NamedTemporaryFile(suffix='_' + apk_name)
Doug Zongkereef39442009-04-02 12:14:19 -0700440 unsigned.write(data)
441 unsigned.flush()
442
Narayan Kamatha07bf042017-08-14 14:49:21 +0100443 if is_compressed:
444 uncompressed = tempfile.NamedTemporaryFile()
Tao Bao0c28d2d2017-12-24 10:37:38 -0800445 with gzip.open(unsigned.name, "rb") as in_file, \
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400446 open(uncompressed.name, "wb") as out_file:
Narayan Kamatha07bf042017-08-14 14:49:21 +0100447 shutil.copyfileobj(in_file, out_file)
448
449 # Finally, close the "unsigned" file (which is gzip compressed), and then
450 # replace it with the uncompressed version.
451 #
452 # TODO(narayan): All this nastiness can be avoided if python 3.2 is in use,
453 # we could just gzip / gunzip in-memory buffers instead.
454 unsigned.close()
455 unsigned = uncompressed
456
Oleg Aravin8046cb02020-06-02 16:02:38 -0700457 signed = tempfile.NamedTemporaryFile(suffix='_' + apk_name)
Doug Zongkereef39442009-04-02 12:14:19 -0700458
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800459 # For pre-N builds, don't upgrade to SHA-256 JAR signatures based on the APK's
460 # minSdkVersion to avoid increasing incremental OTA update sizes. If an APK
461 # didn't change, we don't want its signature to change due to the switch
462 # from SHA-1 to SHA-256.
463 # By default, APK signer chooses SHA-256 signatures if the APK's minSdkVersion
464 # is 18 or higher. For pre-N builds we disable this mechanism by pretending
465 # that the APK's minSdkVersion is 1.
466 # For N+ builds, we let APK signer rely on the APK's minSdkVersion to
467 # determine whether to use SHA-256.
468 min_api_level = None
469 if platform_api_level > 23:
470 # Let APK signer choose whether to use SHA-1 or SHA-256, based on the APK's
471 # minSdkVersion attribute
472 min_api_level = None
473 else:
474 # Force APK signer to use SHA-1
475 min_api_level = 1
476
477 common.SignFile(unsigned.name, signed.name, keyname, pw,
Tao Bao0c28d2d2017-12-24 10:37:38 -0800478 min_api_level=min_api_level,
479 codename_to_api_level_map=codename_to_api_level_map)
Doug Zongkereef39442009-04-02 12:14:19 -0700480
Tao Bao0c28d2d2017-12-24 10:37:38 -0800481 data = None
Narayan Kamatha07bf042017-08-14 14:49:21 +0100482 if is_compressed:
483 # Recompress the file after it has been signed.
484 compressed = tempfile.NamedTemporaryFile()
Tao Bao0c28d2d2017-12-24 10:37:38 -0800485 with open(signed.name, "rb") as in_file, \
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400486 gzip.open(compressed.name, "wb") as out_file:
Narayan Kamatha07bf042017-08-14 14:49:21 +0100487 shutil.copyfileobj(in_file, out_file)
488
489 data = compressed.read()
490 compressed.close()
491 else:
492 data = signed.read()
493
Doug Zongkereef39442009-04-02 12:14:19 -0700494 unsigned.close()
495 signed.close()
496
497 return data
498
Tianjie5bd03952021-02-18 23:02:36 -0800499
Kelvin Zhang119f2792021-02-10 12:45:24 -0500500def IsBuildPropFile(filename):
501 return filename in (
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400502 "SYSTEM/etc/prop.default",
503 "BOOT/RAMDISK/prop.default",
504 "RECOVERY/RAMDISK/prop.default",
Kelvin Zhang119f2792021-02-10 12:45:24 -0500505
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400506 "VENDOR_BOOT/RAMDISK/default.prop",
507 "VENDOR_BOOT/RAMDISK/prop.default",
Kelvin Zhang119f2792021-02-10 12:45:24 -0500508
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400509 # ROOT/default.prop is a legacy path, but may still exist for upgrading
510 # devices that don't support `property_overrides_split_enabled`.
511 "ROOT/default.prop",
Kelvin Zhang119f2792021-02-10 12:45:24 -0500512
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400513 # RECOVERY/RAMDISK/default.prop is a legacy path, but will always exist
514 # as a symlink in the current code. So it's a no-op here. Keeping the
515 # path here for clarity.
516 "RECOVERY/RAMDISK/default.prop") or filename.endswith("build.prop")
Doug Zongkereef39442009-04-02 12:14:19 -0700517
Tianjie5bd03952021-02-18 23:02:36 -0800518
Doug Zongker412c02f2014-02-13 10:58:24 -0800519def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -0700520 apk_keys, apex_keys, key_passwords,
521 platform_api_level, codename_to_api_level_map,
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +0000522 compressed_extension):
Tao Bao93c2a012018-06-19 12:19:35 -0700523 # maxsize measures the maximum filename length, including the ones to be
524 # skipped.
Bowgo Tsai8d4b7242022-01-04 15:15:35 +0800525 try:
526 maxsize = max(
527 [len(os.path.basename(i.filename)) for i in input_tf_zip.infolist()
528 if GetApkFileInfo(i.filename, compressed_extension, [])[0]])
529 except ValueError:
530 # Sets this to zero for targets without APK files, e.g., gki_arm64.
531 maxsize = 0
532
Tao Baoa80ed222016-06-16 14:41:24 -0700533 system_root_image = misc_info.get("system_root_image") == "true"
Doug Zongker412c02f2014-02-13 10:58:24 -0800534
Doug Zongkereef39442009-04-02 12:14:19 -0700535 for info in input_tf_zip.infolist():
Tao Bao11f955c2018-06-19 12:19:35 -0700536 filename = info.filename
537 if filename.startswith("IMAGES/"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700538 continue
Doug Zongker3c84f562014-07-31 11:06:30 -0700539
Tao Bao04808502019-07-25 23:11:41 -0700540 # Skip OTA-specific images (e.g. split super images), which will be
541 # re-generated during signing.
Tao Bao33bf2682019-01-11 12:37:35 -0800542 if filename.startswith("OTA/") and filename.endswith(".img"):
543 continue
544
Tao Bao11f955c2018-06-19 12:19:35 -0700545 data = input_tf_zip.read(filename)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700546 out_info = copy.copy(info)
Tao Bao93c2a012018-06-19 12:19:35 -0700547 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
548 filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
549
550 if is_apk and should_be_skipped:
551 # Copy skipped APKs verbatim.
552 print(
553 "NOT signing: %s\n"
554 " (skipped due to matching prefix)" % (filename,))
555 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker412c02f2014-02-13 10:58:24 -0800556
Tao Baof2cffbd2015-07-22 12:33:18 -0700557 # Sign APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700558 elif is_apk:
Tao Bao11f955c2018-06-19 12:19:35 -0700559 name = os.path.basename(filename)
Narayan Kamatha07bf042017-08-14 14:49:21 +0100560 if is_compressed:
561 name = name[:-len(compressed_extension)]
562
Tao Baoaa7e9932019-03-15 09:37:01 -0700563 key = apk_keys[name]
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800564 if key not in common.SPECIAL_CERT_STRINGS:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800565 print(" signing: %-*s (%s)" % (maxsize, name, key))
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800566 signed_data = SignApk(data, key, key_passwords[key], platform_api_level,
Oleg Aravin8046cb02020-06-02 16:02:38 -0700567 codename_to_api_level_map, is_compressed, name)
Tao Bao2ed665a2015-04-01 11:21:55 -0700568 common.ZipWriteStr(output_tf_zip, out_info, signed_data)
Doug Zongkereef39442009-04-02 12:14:19 -0700569 else:
570 # an APK we're not supposed to sign.
Tao Bao93c2a012018-06-19 12:19:35 -0700571 print(
572 "NOT signing: %s\n"
573 " (skipped due to special cert string)" % (name,))
Tao Bao2ed665a2015-04-01 11:21:55 -0700574 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoa80ed222016-06-16 14:41:24 -0700575
Tianjie5bd03952021-02-18 23:02:36 -0800576 # Sign bundled APEX files on all partitions
Tianjie4d48d502021-06-11 17:03:43 -0700577 elif IsApexFile(filename):
578 name = GetApexFilename(filename)
579
Jooyung Han8caba5e2021-10-27 03:58:09 +0900580 payload_key, container_key, sign_tool = apex_keys[name]
Tao Baoaa7e9932019-03-15 09:37:01 -0700581
Tao Baoe1343992019-03-19 12:24:03 -0700582 # We've asserted not having a case with only one of them PRESIGNED.
583 if (payload_key not in common.SPECIAL_CERT_STRINGS and
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400584 container_key not in common.SPECIAL_CERT_STRINGS):
Tao Baoe1343992019-03-19 12:24:03 -0700585 print(" signing: %-*s container (%s)" % (
586 maxsize, name, container_key))
587 print(" : %-*s payload (%s)" % (
588 maxsize, name, payload_key))
Tao Baoaa7e9932019-03-15 09:37:01 -0700589
Tao Baoe7354ba2019-05-09 16:54:15 -0700590 signed_apex = apex_utils.SignApex(
Tao Bao1ac886e2019-06-26 11:58:22 -0700591 misc_info['avb_avbtool'],
Tao Baoe1343992019-03-19 12:24:03 -0700592 data,
593 payload_key,
594 container_key,
Oleh Cherpake555ab12020-10-05 17:04:59 +0300595 key_passwords,
Tianjie Xu88a759d2020-01-23 10:47:54 -0800596 apk_keys,
Tao Baoe1343992019-03-19 12:24:03 -0700597 codename_to_api_level_map,
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400598 no_hashtree=None, # Let apex_util determine if hash tree is needed
Jooyung Han8caba5e2021-10-27 03:58:09 +0900599 signing_args=OPTIONS.avb_extra_args.get('apex'),
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +0000600 sign_tool=sign_tool)
Tao Baoe1343992019-03-19 12:24:03 -0700601 common.ZipWrite(output_tf_zip, signed_apex, filename)
Tao Baoaa7e9932019-03-15 09:37:01 -0700602
Tao Baoe1343992019-03-19 12:24:03 -0700603 else:
604 print(
605 "NOT signing: %s\n"
606 " (skipped due to special cert string)" % (name,))
607 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoaa7e9932019-03-15 09:37:01 -0700608
Tao Baoa80ed222016-06-16 14:41:24 -0700609 # System properties.
Kelvin Zhang119f2792021-02-10 12:45:24 -0500610 elif IsBuildPropFile(filename):
Tao Bao11f955c2018-06-19 12:19:35 -0700611 print("Rewriting %s:" % (filename,))
Hung-ying Tyan7eb6a922017-05-01 21:56:26 +0800612 if stat.S_ISLNK(info.external_attr >> 16):
613 new_data = data
614 else:
Tao Baoa3705452019-06-24 15:33:41 -0700615 new_data = RewriteProps(data.decode())
Tao Bao2ed665a2015-04-01 11:21:55 -0700616 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700617
Tao Bao66472632017-12-04 17:16:36 -0800618 # Replace the certs in *mac_permissions.xml (there could be multiple, such
Inseob Kime7b222a2021-12-21 15:57:03 +0900619 # as {system,vendor}/etc/selinux/{plat,vendor}_mac_permissions.xml).
Tao Bao11f955c2018-06-19 12:19:35 -0700620 elif filename.endswith("mac_permissions.xml"):
621 print("Rewriting %s with new keys." % (filename,))
Tao Baoa3705452019-06-24 15:33:41 -0700622 new_data = ReplaceCerts(data.decode())
Tao Bao2ed665a2015-04-01 11:21:55 -0700623 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700624
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700625 # Ask add_img_to_target_files to rebuild the recovery patch if needed.
Tao Bao11f955c2018-06-19 12:19:35 -0700626 elif filename in ("SYSTEM/recovery-from-boot.p",
Robin Leeda427de2020-01-03 19:16:32 +0100627 "VENDOR/recovery-from-boot.p",
628
Tao Bao11f955c2018-06-19 12:19:35 -0700629 "SYSTEM/etc/recovery.img",
Robin Leeda427de2020-01-03 19:16:32 +0100630 "VENDOR/etc/recovery.img",
631
632 "SYSTEM/bin/install-recovery.sh",
633 "VENDOR/bin/install-recovery.sh"):
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700634 OPTIONS.rebuild_recovery = True
Tao Baoa80ed222016-06-16 14:41:24 -0700635
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700636 # Don't copy OTA certs if we're replacing them.
Tianjie Xu2df23d72019-10-15 18:06:25 -0700637 # Replacement of update-payload-key.pub.pem was removed in b/116660991.
Kelvin Zhang9f781ff2021-02-11 19:10:44 -0500638 elif OPTIONS.replace_ota_keys and filename.endswith("/otacerts.zip"):
Doug Zongker412c02f2014-02-13 10:58:24 -0800639 pass
Tao Baoa80ed222016-06-16 14:41:24 -0700640
Tao Bao46a59992017-06-05 11:55:16 -0700641 # Skip META/misc_info.txt since we will write back the new values later.
Tao Bao11f955c2018-06-19 12:19:35 -0700642 elif filename == "META/misc_info.txt":
Geremy Condraf19b3652014-07-29 17:54:54 -0700643 pass
Tao Bao8adcfd12016-06-17 17:01:22 -0700644
645 # Skip verity public key if we will replace it.
Michael Runge947894f2014-10-14 20:58:38 -0700646 elif (OPTIONS.replace_verity_public_key and
Tao Bao11f955c2018-06-19 12:19:35 -0700647 filename in ("BOOT/RAMDISK/verity_key",
648 "ROOT/verity_key")):
Geremy Condraf19b3652014-07-29 17:54:54 -0700649 pass
Bowgo Tsai2fe786a2020-02-21 17:48:18 +0800650 elif (OPTIONS.remove_avb_public_keys and
651 (filename.startswith("BOOT/RAMDISK/avb/") or
652 filename.startswith("BOOT/RAMDISK/first_stage_ramdisk/avb/"))):
Kelvin Zhang0876c412020-06-23 15:06:58 -0400653 matched_removal = False
654 for key_to_remove in OPTIONS.remove_avb_public_keys:
655 if filename.endswith(key_to_remove):
656 matched_removal = True
657 print("Removing AVB public key from ramdisk: %s" % filename)
658 break
659 if not matched_removal:
660 # Copy it verbatim if we don't want to remove it.
661 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoa80ed222016-06-16 14:41:24 -0700662
Tao Bao8adcfd12016-06-17 17:01:22 -0700663 # Skip verity keyid (for system_root_image use) if we will replace it.
Tao Bao11f955c2018-06-19 12:19:35 -0700664 elif OPTIONS.replace_verity_keyid and filename == "BOOT/cmdline":
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700665 pass
666
Tianjiebbde59f2021-05-03 21:18:56 -0700667 # Skip the vbmeta digest as we will recalculate it.
668 elif filename == "META/vbmeta_digest.txt":
669 pass
670
Tianjie Xu4f099002016-08-11 18:04:27 -0700671 # Skip the care_map as we will regenerate the system/vendor images.
Kelvin Zhang0876c412020-06-23 15:06:58 -0400672 elif filename in ["META/care_map.pb", "META/care_map.txt"]:
Tianjie Xu4f099002016-08-11 18:04:27 -0700673 pass
674
Kelvin Zhang5f0fcee2021-01-19 15:30:46 -0500675 # Skip apex_info.pb because we sign/modify apexes
676 elif filename == "META/apex_info.pb":
677 pass
678
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800679 # Updates system_other.avbpubkey in /product/etc/.
680 elif filename in (
681 "PRODUCT/etc/security/avb/system_other.avbpubkey",
Bowgo Tsai2a781692021-10-13 17:39:33 +0800682 "SYSTEM/product/etc/security/avb/system_other.avbpubkey"):
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800683 # Only update system_other's public key, if the corresponding signing
684 # key is specified via --avb_system_other_key.
685 signing_key = OPTIONS.avb_keys.get("system_other")
686 if signing_key:
Tao Bao1ac886e2019-06-26 11:58:22 -0700687 public_key = common.ExtractAvbPublicKey(
688 misc_info['avb_avbtool'], signing_key)
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800689 print(" Rewriting AVB public key of system_other in /product")
690 common.ZipWrite(output_tf_zip, public_key, filename)
691
Andrew Scullbbc930b2022-02-17 22:34:27 +0000692 # Updates pvmfw embedded public key with the virt APEX payload key.
693 elif filename == "PREBUILT_IMAGES/pvmfw.img":
694 # Find the name of the virt APEX in the target files.
695 namelist = input_tf_zip.namelist()
696 apex_gen = (GetApexFilename(f) for f in namelist if IsApexFile(f))
697 virt_apex_re = re.compile("^com\.([^\.]+\.)?android\.virt\.apex$")
698 virt_apex = next((a for a in apex_gen if virt_apex_re.match(a)), None)
699 if not virt_apex:
700 print("Removing %s from ramdisk: virt APEX not found" % filename)
701 else:
702 print("Replacing %s embedded key with %s key" % (filename, virt_apex))
703 # Get the current and new embedded keys.
704 payload_key, container_key, sign_tool = apex_keys[virt_apex]
705 new_pubkey_path = common.ExtractAvbPublicKey(
706 misc_info['avb_avbtool'], payload_key)
707 with open(new_pubkey_path, 'rb') as f:
708 new_pubkey = f.read()
709 pubkey_info = copy.copy(
710 input_tf_zip.getinfo("PREBUILT_IMAGES/pvmfw_embedded.avbpubkey"))
711 old_pubkey = input_tf_zip.read(pubkey_info.filename)
712 # Validate the keys and image.
713 if len(old_pubkey) != len(new_pubkey):
714 raise common.ExternalError("pvmfw embedded public key size mismatch")
715 pos = data.find(old_pubkey)
716 if pos == -1:
717 raise common.ExternalError("pvmfw embedded public key not found")
718 # Replace the key and copy new files.
719 new_data = data[:pos] + new_pubkey + data[pos+len(old_pubkey):]
720 common.ZipWriteStr(output_tf_zip, out_info, new_data)
721 common.ZipWriteStr(output_tf_zip, pubkey_info, new_pubkey)
722 elif filename == "PREBUILT_IMAGES/pvmfw_embedded.avbpubkey":
723 pass
724
Bowgo Tsai78369eb2019-04-23 12:28:44 +0800725 # Should NOT sign boot-debug.img.
726 elif filename in (
727 "BOOT/RAMDISK/force_debuggable",
Bowgo Tsai2a781692021-10-13 17:39:33 +0800728 "BOOT/RAMDISK/first_stage_ramdisk/force_debuggable"):
Bowgo Tsai78369eb2019-04-23 12:28:44 +0800729 raise common.ExternalError("debuggable boot.img cannot be signed")
730
Bowgo Tsai2a781692021-10-13 17:39:33 +0800731 # Should NOT sign userdebug sepolicy file.
732 elif filename in (
733 "SYSTEM_EXT/etc/selinux/userdebug_plat_sepolicy.cil",
734 "SYSTEM/system_ext/etc/selinux/userdebug_plat_sepolicy.cil"):
735 if not OPTIONS.allow_gsi_debug_sepolicy:
736 raise common.ExternalError("debug sepolicy shouldn't be included")
737 else:
738 # Copy it verbatim if we allow the file to exist.
739 common.ZipWriteStr(output_tf_zip, out_info, data)
740
Tao Baoa80ed222016-06-16 14:41:24 -0700741 # A non-APK file; copy it verbatim.
Doug Zongkereef39442009-04-02 12:14:19 -0700742 else:
Tao Bao2ed665a2015-04-01 11:21:55 -0700743 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700744
Doug Zongker412c02f2014-02-13 10:58:24 -0800745 if OPTIONS.replace_ota_keys:
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700746 ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info)
Doug Zongker412c02f2014-02-13 10:58:24 -0800747
Tao Bao46a59992017-06-05 11:55:16 -0700748 # Replace the keyid string in misc_info dict.
Tao Bao8adcfd12016-06-17 17:01:22 -0700749 if OPTIONS.replace_verity_private_key:
Tao Bao46a59992017-06-05 11:55:16 -0700750 ReplaceVerityPrivateKey(misc_info, OPTIONS.replace_verity_private_key[1])
Tao Bao8adcfd12016-06-17 17:01:22 -0700751
752 if OPTIONS.replace_verity_public_key:
Tao Baoc9981932019-09-16 12:10:43 -0700753 # Replace the one in root dir in system.img.
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700754 ReplaceVerityPublicKey(
Tao Baoc9981932019-09-16 12:10:43 -0700755 output_tf_zip, 'ROOT/verity_key', OPTIONS.replace_verity_public_key[1])
756
757 if not system_root_image:
758 # Additionally replace the copy in ramdisk if not using system-as-root.
759 ReplaceVerityPublicKey(
760 output_tf_zip,
761 'BOOT/RAMDISK/verity_key',
762 OPTIONS.replace_verity_public_key[1])
Tao Bao8adcfd12016-06-17 17:01:22 -0700763
764 # Replace the keyid string in BOOT/cmdline.
765 if OPTIONS.replace_verity_keyid:
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700766 ReplaceVerityKeyId(input_tf_zip, output_tf_zip,
767 OPTIONS.replace_verity_keyid[1])
Doug Zongker412c02f2014-02-13 10:58:24 -0800768
Tao Bao639118f2017-06-19 15:48:02 -0700769 # Replace the AVB signing keys, if any.
770 ReplaceAvbSigningKeys(misc_info)
771
Tao Bao19b02fe2019-10-09 00:04:28 -0700772 # Rewrite the props in AVB signing args.
773 if misc_info.get('avb_enable') == 'true':
774 RewriteAvbProps(misc_info)
775
Bowgo Tsai27c39b02021-03-12 21:40:32 +0800776 # Replace the GKI signing key for boot.img, if any.
777 ReplaceGkiSigningKey(misc_info)
778
Tao Bao46a59992017-06-05 11:55:16 -0700779 # Write back misc_info with the latest values.
780 ReplaceMiscInfoTxt(input_tf_zip, output_tf_zip, misc_info)
781
Doug Zongker8e931bf2009-04-06 15:21:45 -0700782
Robert Craig817c5742013-04-19 10:59:22 -0400783def ReplaceCerts(data):
Tao Bao66472632017-12-04 17:16:36 -0800784 """Replaces all the occurences of X.509 certs with the new ones.
Robert Craig817c5742013-04-19 10:59:22 -0400785
Tao Bao66472632017-12-04 17:16:36 -0800786 The mapping info is read from OPTIONS.key_map. Non-existent certificate will
787 be skipped. After the replacement, it additionally checks for duplicate
788 entries, which would otherwise fail the policy loading code in
789 frameworks/base/services/core/java/com/android/server/pm/SELinuxMMAC.java.
790
791 Args:
792 data: Input string that contains a set of X.509 certs.
793
794 Returns:
795 A string after the replacement.
796
797 Raises:
798 AssertionError: On finding duplicate entries.
799 """
Tao Baoa3705452019-06-24 15:33:41 -0700800 for old, new in OPTIONS.key_map.items():
Tao Bao66472632017-12-04 17:16:36 -0800801 if OPTIONS.verbose:
802 print(" Replacing %s.x509.pem with %s.x509.pem" % (old, new))
803
804 try:
805 with open(old + ".x509.pem") as old_fp:
806 old_cert16 = base64.b16encode(
Tao Baoa3705452019-06-24 15:33:41 -0700807 common.ParseCertificate(old_fp.read())).decode().lower()
Tao Bao66472632017-12-04 17:16:36 -0800808 with open(new + ".x509.pem") as new_fp:
809 new_cert16 = base64.b16encode(
Tao Baoa3705452019-06-24 15:33:41 -0700810 common.ParseCertificate(new_fp.read())).decode().lower()
Tao Bao66472632017-12-04 17:16:36 -0800811 except IOError as e:
812 if OPTIONS.verbose or e.errno != errno.ENOENT:
813 print(" Error accessing %s: %s.\nSkip replacing %s.x509.pem with "
814 "%s.x509.pem." % (e.filename, e.strerror, old, new))
815 continue
816
817 # Only match entire certs.
818 pattern = "\\b" + old_cert16 + "\\b"
819 (data, num) = re.subn(pattern, new_cert16, data, flags=re.IGNORECASE)
820
821 if OPTIONS.verbose:
822 print(" Replaced %d occurence(s) of %s.x509.pem with %s.x509.pem" % (
823 num, old, new))
824
825 # Verify that there're no duplicate entries after the replacement. Note that
826 # it's only checking entries with global seinfo at the moment (i.e. ignoring
827 # the ones with inner packages). (Bug: 69479366)
828 root = ElementTree.fromstring(data)
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400829 signatures = [signer.attrib['signature']
830 for signer in root.findall('signer')]
Tao Bao66472632017-12-04 17:16:36 -0800831 assert len(signatures) == len(set(signatures)), \
832 "Found duplicate entries after cert replacement: {}".format(data)
Robert Craig817c5742013-04-19 10:59:22 -0400833
834 return data
835
836
Doug Zongkerc09abc82010-01-11 13:09:15 -0800837def EditTags(tags):
Tao Baoa7054ee2017-12-08 14:42:16 -0800838 """Applies the edits to the tag string as specified in OPTIONS.tag_changes.
839
840 Args:
841 tags: The input string that contains comma-separated tags.
842
843 Returns:
844 The updated tags (comma-separated and sorted).
845 """
Doug Zongkerc09abc82010-01-11 13:09:15 -0800846 tags = set(tags.split(","))
847 for ch in OPTIONS.tag_changes:
848 if ch[0] == "-":
849 tags.discard(ch[1:])
850 elif ch[0] == "+":
851 tags.add(ch[1:])
852 return ",".join(sorted(tags))
853
854
Tao Baoa7054ee2017-12-08 14:42:16 -0800855def RewriteProps(data):
856 """Rewrites the system properties in the given string.
857
858 Each property is expected in 'key=value' format. The properties that contain
859 build tags (i.e. test-keys, dev-keys) will be updated accordingly by calling
860 EditTags().
861
862 Args:
863 data: Input string, separated by newlines.
864
865 Returns:
866 The string with modified properties.
867 """
Doug Zongker17aa9442009-04-17 10:15:58 -0700868 output = []
869 for line in data.split("\n"):
870 line = line.strip()
871 original_line = line
Michael Rungedc2661a2014-06-03 14:43:11 -0700872 if line and line[0] != '#' and "=" in line:
Doug Zongker17aa9442009-04-17 10:15:58 -0700873 key, value = line.split("=", 1)
Magnus Strandh234f4b42019-05-01 23:09:30 +0200874 if (key.startswith("ro.") and
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400875 key.endswith((".build.fingerprint", ".build.thumbprint"))):
Doug Zongkerc09abc82010-01-11 13:09:15 -0800876 pieces = value.split("/")
877 pieces[-1] = EditTags(pieces[-1])
878 value = "/".join(pieces)
Tao Baocb7ff772015-09-11 15:27:56 -0700879 elif key == "ro.bootimage.build.fingerprint":
880 pieces = value.split("/")
881 pieces[-1] = EditTags(pieces[-1])
882 value = "/".join(pieces)
Doug Zongker17aa9442009-04-17 10:15:58 -0700883 elif key == "ro.build.description":
Doug Zongkerc09abc82010-01-11 13:09:15 -0800884 pieces = value.split(" ")
Stefen Wakefield4260fc12021-03-23 04:58:22 -0500885 assert pieces[-1].endswith("-keys")
Doug Zongkerc09abc82010-01-11 13:09:15 -0800886 pieces[-1] = EditTags(pieces[-1])
887 value = " ".join(pieces)
Magnus Strandh234f4b42019-05-01 23:09:30 +0200888 elif key.startswith("ro.") and key.endswith(".build.tags"):
Doug Zongkerc09abc82010-01-11 13:09:15 -0800889 value = EditTags(value)
Doug Zongkera8608a72013-07-23 11:51:04 -0700890 elif key == "ro.build.display.id":
891 # change, eg, "JWR66N dev-keys" to "JWR66N"
892 value = value.split()
Michael Rungedc2661a2014-06-03 14:43:11 -0700893 if len(value) > 1 and value[-1].endswith("-keys"):
Andrew Boie73d5abb2013-12-11 12:42:03 -0800894 value.pop()
895 value = " ".join(value)
Doug Zongkerc09abc82010-01-11 13:09:15 -0800896 line = key + "=" + value
Doug Zongker17aa9442009-04-17 10:15:58 -0700897 if line != original_line:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800898 print(" replace: ", original_line)
899 print(" with: ", line)
Doug Zongker17aa9442009-04-17 10:15:58 -0700900 output.append(line)
901 return "\n".join(output) + "\n"
902
903
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700904def WriteOtacerts(output_zip, filename, keys):
905 """Constructs a zipfile from given keys; and writes it to output_zip.
906
907 Args:
908 output_zip: The output target_files zip.
909 filename: The archive name in the output zip.
910 keys: A list of public keys to use during OTA package verification.
911 """
Tao Baobb733882019-07-24 23:31:19 -0700912 temp_file = io.BytesIO()
Kelvin Zhang928c2342020-09-22 16:15:57 -0400913 certs_zip = zipfile.ZipFile(temp_file, "w", allowZip64=True)
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700914 for k in keys:
915 common.ZipWrite(certs_zip, k)
916 common.ZipClose(certs_zip)
917 common.ZipWriteStr(output_zip, filename, temp_file.getvalue())
918
919
Doug Zongker831840e2011-09-22 10:28:04 -0700920def ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info):
Doug Zongker8e931bf2009-04-06 15:21:45 -0700921 try:
922 keylist = input_tf_zip.read("META/otakeys.txt").split()
923 except KeyError:
T.R. Fullharta28acc62013-03-18 10:31:26 -0700924 raise common.ExternalError("can't read META/otakeys.txt from input")
Doug Zongker8e931bf2009-04-06 15:21:45 -0700925
Jacky Liubeb0b692021-12-29 16:29:05 +0800926 extra_ota_keys_info = misc_info.get("extra_ota_keys")
927 if extra_ota_keys_info:
928 extra_ota_keys = [OPTIONS.key_map.get(k, k) + ".x509.pem"
929 for k in extra_ota_keys_info.split()]
930 print("extra ota key(s): " + ", ".join(extra_ota_keys))
931 else:
932 extra_ota_keys = []
933 for k in extra_ota_keys:
934 if not os.path.isfile(k):
935 raise common.ExternalError(k + " does not exist or is not a file")
936
937 extra_recovery_keys_info = misc_info.get("extra_recovery_keys")
938 if extra_recovery_keys_info:
Doug Zongkere121d6a2011-02-01 14:13:52 -0800939 extra_recovery_keys = [OPTIONS.key_map.get(k, k) + ".x509.pem"
Jacky Liubeb0b692021-12-29 16:29:05 +0800940 for k in extra_recovery_keys_info.split()]
941 print("extra recovery-only key(s): " + ", ".join(extra_recovery_keys))
Doug Zongkere121d6a2011-02-01 14:13:52 -0800942 else:
943 extra_recovery_keys = []
Jacky Liubeb0b692021-12-29 16:29:05 +0800944 for k in extra_recovery_keys:
945 if not os.path.isfile(k):
946 raise common.ExternalError(k + " does not exist or is not a file")
Doug Zongkere121d6a2011-02-01 14:13:52 -0800947
Doug Zongker8e931bf2009-04-06 15:21:45 -0700948 mapped_keys = []
949 for k in keylist:
950 m = re.match(r"^(.*)\.x509\.pem$", k)
951 if not m:
Doug Zongker412c02f2014-02-13 10:58:24 -0800952 raise common.ExternalError(
953 "can't parse \"%s\" from META/otakeys.txt" % (k,))
Doug Zongker8e931bf2009-04-06 15:21:45 -0700954 k = m.group(1)
955 mapped_keys.append(OPTIONS.key_map.get(k, k) + ".x509.pem")
956
Doug Zongkere05628c2009-08-20 17:38:42 -0700957 if mapped_keys:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800958 print("using:\n ", "\n ".join(mapped_keys))
959 print("for OTA package verification")
Doug Zongkere05628c2009-08-20 17:38:42 -0700960 else:
Doug Zongker831840e2011-09-22 10:28:04 -0700961 devkey = misc_info.get("default_system_dev_certificate",
Dan Willemsen0ab1be62019-04-09 21:35:37 -0700962 "build/make/target/product/security/testkey")
Tao Baof718f902017-11-09 10:10:10 -0800963 mapped_devkey = OPTIONS.key_map.get(devkey, devkey)
964 if mapped_devkey != devkey:
965 misc_info["default_system_dev_certificate"] = mapped_devkey
966 mapped_keys.append(mapped_devkey + ".x509.pem")
Tao Baoa80ed222016-06-16 14:41:24 -0700967 print("META/otakeys.txt has no keys; using %s for OTA package"
968 " verification." % (mapped_keys[0],))
Jacky Liubeb0b692021-12-29 16:29:05 +0800969 for k in mapped_keys:
970 if not os.path.isfile(k):
971 raise common.ExternalError(k + " does not exist or is not a file")
Doug Zongker8e931bf2009-04-06 15:21:45 -0700972
Kelvin Zhang9f781ff2021-02-11 19:10:44 -0500973 otacerts = [info
974 for info in input_tf_zip.infolist()
975 if info.filename.endswith("/otacerts.zip")]
976 for info in otacerts:
Jacky Liubeb0b692021-12-29 16:29:05 +0800977 if info.filename.startswith(("BOOT/", "RECOVERY/", "VENDOR_BOOT/")):
978 extra_keys = extra_recovery_keys
979 else:
980 extra_keys = extra_ota_keys
981 print("Rewriting OTA key:", info.filename, mapped_keys + extra_keys)
982 WriteOtacerts(output_tf_zip, info.filename, mapped_keys + extra_keys)
Doug Zongkereef39442009-04-02 12:14:19 -0700983
Tao Baoa80ed222016-06-16 14:41:24 -0700984
Tao Bao0c28d2d2017-12-24 10:37:38 -0800985def ReplaceVerityPublicKey(output_zip, filename, key_path):
986 """Replaces the verity public key at the given path in the given zip.
987
988 Args:
989 output_zip: The output target_files zip.
990 filename: The archive name in the output zip.
991 key_path: The path to the public key.
992 """
993 print("Replacing verity public key with %s" % (key_path,))
994 common.ZipWrite(output_zip, key_path, arcname=filename)
Geremy Condraf19b3652014-07-29 17:54:54 -0700995
Tao Bao8adcfd12016-06-17 17:01:22 -0700996
Tao Bao46a59992017-06-05 11:55:16 -0700997def ReplaceVerityPrivateKey(misc_info, key_path):
Tao Bao0c28d2d2017-12-24 10:37:38 -0800998 """Replaces the verity private key in misc_info dict.
999
1000 Args:
1001 misc_info: The info dict.
1002 key_path: The path to the private key in PKCS#8 format.
1003 """
1004 print("Replacing verity private key with %s" % (key_path,))
Andrew Boied083f0b2014-09-15 16:01:07 -07001005 misc_info["verity_key"] = key_path
Doug Zongkereef39442009-04-02 12:14:19 -07001006
Tao Bao8adcfd12016-06-17 17:01:22 -07001007
Tao Baoe838d142017-12-23 23:44:48 -08001008def ReplaceVerityKeyId(input_zip, output_zip, key_path):
1009 """Replaces the veritykeyid parameter in BOOT/cmdline.
1010
1011 Args:
1012 input_zip: The input target_files zip, which should be already open.
1013 output_zip: The output target_files zip, which should be already open and
1014 writable.
1015 key_path: The path to the PEM encoded X.509 certificate.
1016 """
Tao Baoa3705452019-06-24 15:33:41 -07001017 in_cmdline = input_zip.read("BOOT/cmdline").decode()
Tao Baoe838d142017-12-23 23:44:48 -08001018 # Copy in_cmdline to output_zip if veritykeyid is not present.
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001019 if "veritykeyid" not in in_cmdline:
Tao Baoe838d142017-12-23 23:44:48 -08001020 common.ZipWriteStr(output_zip, "BOOT/cmdline", in_cmdline)
1021 return
1022
Tao Bao0c28d2d2017-12-24 10:37:38 -08001023 out_buffer = []
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001024 for param in in_cmdline.split():
Tao Baoe838d142017-12-23 23:44:48 -08001025 if "veritykeyid" not in param:
Tao Bao0c28d2d2017-12-24 10:37:38 -08001026 out_buffer.append(param)
Tao Baoe838d142017-12-23 23:44:48 -08001027 continue
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001028
Tao Baoe838d142017-12-23 23:44:48 -08001029 # Extract keyid using openssl command.
1030 p = common.Run(["openssl", "x509", "-in", key_path, "-text"],
Tao Baode1d4792018-02-20 10:05:46 -08001031 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
Tao Baoe838d142017-12-23 23:44:48 -08001032 keyid, stderr = p.communicate()
1033 assert p.returncode == 0, "Failed to dump certificate: {}".format(stderr)
1034 keyid = re.search(
1035 r'keyid:([0-9a-fA-F:]*)', keyid).group(1).replace(':', '').lower()
1036 print("Replacing verity keyid with {}".format(keyid))
1037 out_buffer.append("veritykeyid=id:%s" % (keyid,))
1038
1039 out_cmdline = ' '.join(out_buffer).strip() + '\n'
1040 common.ZipWriteStr(output_zip, "BOOT/cmdline", out_cmdline)
Tao Bao46a59992017-06-05 11:55:16 -07001041
1042
1043def ReplaceMiscInfoTxt(input_zip, output_zip, misc_info):
1044 """Replaces META/misc_info.txt.
1045
1046 Only writes back the ones in the original META/misc_info.txt. Because the
1047 current in-memory dict contains additional items computed at runtime.
1048 """
1049 misc_info_old = common.LoadDictionaryFromLines(
Tao Baoa3705452019-06-24 15:33:41 -07001050 input_zip.read('META/misc_info.txt').decode().split('\n'))
Tao Bao46a59992017-06-05 11:55:16 -07001051 items = []
1052 for key in sorted(misc_info):
1053 if key in misc_info_old:
1054 items.append('%s=%s' % (key, misc_info[key]))
1055 common.ZipWriteStr(output_zip, "META/misc_info.txt", '\n'.join(items))
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001056
Tao Bao8adcfd12016-06-17 17:01:22 -07001057
Tao Bao639118f2017-06-19 15:48:02 -07001058def ReplaceAvbSigningKeys(misc_info):
1059 """Replaces the AVB signing keys."""
1060
Tao Bao639118f2017-06-19 15:48:02 -07001061 def ReplaceAvbPartitionSigningKey(partition):
1062 key = OPTIONS.avb_keys.get(partition)
1063 if not key:
1064 return
1065
1066 algorithm = OPTIONS.avb_algorithms.get(partition)
1067 assert algorithm, 'Missing AVB signing algorithm for %s' % (partition,)
1068
Tao Bao0c28d2d2017-12-24 10:37:38 -08001069 print('Replacing AVB signing key for %s with "%s" (%s)' % (
1070 partition, key, algorithm))
Tao Bao639118f2017-06-19 15:48:02 -07001071 misc_info['avb_' + partition + '_algorithm'] = algorithm
1072 misc_info['avb_' + partition + '_key_path'] = key
1073
1074 extra_args = OPTIONS.avb_extra_args.get(partition)
1075 if extra_args:
Tao Bao0c28d2d2017-12-24 10:37:38 -08001076 print('Setting extra AVB signing args for %s to "%s"' % (
1077 partition, extra_args))
Kelvin Zhang0876c412020-06-23 15:06:58 -04001078 args_key = AVB_FOOTER_ARGS_BY_PARTITION.get(
1079 partition,
1080 # custom partition
1081 "avb_{}_add_hashtree_footer_args".format(partition))
Tao Bao639118f2017-06-19 15:48:02 -07001082 misc_info[args_key] = (misc_info.get(args_key, '') + ' ' + extra_args)
1083
1084 for partition in AVB_FOOTER_ARGS_BY_PARTITION:
1085 ReplaceAvbPartitionSigningKey(partition)
1086
Hongguang Chenf23364d2020-04-27 18:36:36 -07001087 for custom_partition in misc_info.get(
Kelvin Zhang7cab7502021-08-02 19:58:14 -04001088 "avb_custom_images_partition_list", "").strip().split():
Hongguang Chenf23364d2020-04-27 18:36:36 -07001089 ReplaceAvbPartitionSigningKey(custom_partition)
1090
Tao Bao639118f2017-06-19 15:48:02 -07001091
Tao Bao19b02fe2019-10-09 00:04:28 -07001092def RewriteAvbProps(misc_info):
1093 """Rewrites the props in AVB signing args."""
1094 for partition, args_key in AVB_FOOTER_ARGS_BY_PARTITION.items():
1095 args = misc_info.get(args_key)
1096 if not args:
1097 continue
1098
1099 tokens = []
1100 changed = False
1101 for token in args.split(' '):
1102 fingerprint_key = 'com.android.build.{}.fingerprint'.format(partition)
1103 if not token.startswith(fingerprint_key):
1104 tokens.append(token)
1105 continue
1106 prefix, tag = token.rsplit('/', 1)
1107 tokens.append('{}/{}'.format(prefix, EditTags(tag)))
1108 changed = True
1109
1110 if changed:
1111 result = ' '.join(tokens)
1112 print('Rewriting AVB prop for {}:\n'.format(partition))
1113 print(' replace: {}'.format(args))
1114 print(' with: {}'.format(result))
1115 misc_info[args_key] = result
1116
1117
Bowgo Tsai27c39b02021-03-12 21:40:32 +08001118def ReplaceGkiSigningKey(misc_info):
1119 """Replaces the GKI signing key."""
1120
1121 key = OPTIONS.gki_signing_key
1122 if not key:
1123 return
1124
1125 algorithm = OPTIONS.gki_signing_algorithm
1126 if not algorithm:
1127 raise ValueError("Missing --gki_signing_algorithm")
1128
1129 print('Replacing GKI signing key with "%s" (%s)' % (key, algorithm))
1130 misc_info["gki_signing_algorithm"] = algorithm
1131 misc_info["gki_signing_key_path"] = key
1132
1133 extra_args = OPTIONS.gki_signing_extra_args
1134 if extra_args:
Bowgo Tsaibcae74d2021-05-10 17:35:37 +08001135 print('Setting GKI signing args: "%s"' % (extra_args))
1136 misc_info["gki_signing_signature_args"] = extra_args
Bowgo Tsai27c39b02021-03-12 21:40:32 +08001137
1138
Doug Zongker831840e2011-09-22 10:28:04 -07001139def BuildKeyMap(misc_info, key_mapping_options):
1140 for s, d in key_mapping_options:
1141 if s is None: # -d option
1142 devkey = misc_info.get("default_system_dev_certificate",
Dan Willemsen0ab1be62019-04-09 21:35:37 -07001143 "build/make/target/product/security/testkey")
Doug Zongker831840e2011-09-22 10:28:04 -07001144 devkeydir = os.path.dirname(devkey)
1145
1146 OPTIONS.key_map.update({
1147 devkeydir + "/testkey": d + "/releasekey",
1148 devkeydir + "/devkey": d + "/releasekey",
1149 devkeydir + "/media": d + "/media",
1150 devkeydir + "/shared": d + "/shared",
1151 devkeydir + "/platform": d + "/platform",
Oleh Cherpak982e6082019-12-10 12:58:54 +02001152 devkeydir + "/networkstack": d + "/networkstack",
Kelvin Zhang7cab7502021-08-02 19:58:14 -04001153 })
Doug Zongker831840e2011-09-22 10:28:04 -07001154 else:
1155 OPTIONS.key_map[s] = d
1156
1157
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001158def GetApiLevelAndCodename(input_tf_zip):
Tao Baoa3705452019-06-24 15:33:41 -07001159 data = input_tf_zip.read("SYSTEM/build.prop").decode()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001160 api_level = None
1161 codename = None
1162 for line in data.split("\n"):
1163 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001164 if line and line[0] != '#' and "=" in line:
1165 key, value = line.split("=", 1)
1166 key = key.strip()
1167 if key == "ro.build.version.sdk":
1168 api_level = int(value.strip())
1169 elif key == "ro.build.version.codename":
1170 codename = value.strip()
1171
1172 if api_level is None:
1173 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
1174 if codename is None:
1175 raise ValueError("No ro.build.version.codename in SYSTEM/build.prop")
1176
1177 return (api_level, codename)
1178
1179
1180def GetCodenameToApiLevelMap(input_tf_zip):
Tao Baoa3705452019-06-24 15:33:41 -07001181 data = input_tf_zip.read("SYSTEM/build.prop").decode()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001182 api_level = None
1183 codenames = None
1184 for line in data.split("\n"):
1185 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001186 if line and line[0] != '#' and "=" in line:
1187 key, value = line.split("=", 1)
1188 key = key.strip()
1189 if key == "ro.build.version.sdk":
1190 api_level = int(value.strip())
1191 elif key == "ro.build.version.all_codenames":
1192 codenames = value.strip().split(",")
1193
1194 if api_level is None:
1195 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
1196 if codenames is None:
1197 raise ValueError("No ro.build.version.all_codenames in SYSTEM/build.prop")
1198
Tao Baoa3705452019-06-24 15:33:41 -07001199 result = {}
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001200 for codename in codenames:
1201 codename = codename.strip()
Tao Baobadceb22019-03-15 09:33:43 -07001202 if codename:
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001203 result[codename] = api_level
1204 return result
1205
1206
Tao Baoaa7e9932019-03-15 09:37:01 -07001207def ReadApexKeysInfo(tf_zip):
1208 """Parses the APEX keys info from a given target-files zip.
1209
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001210 Given a target-files ZipFile, parses the META/apexkeys.txt entry and returns a
1211 dict that contains the mapping from APEX names (e.g. com.android.tzdata) to a
1212 tuple of (payload_key, container_key, sign_tool).
Tao Baoaa7e9932019-03-15 09:37:01 -07001213
1214 Args:
1215 tf_zip: The input target_files ZipFile (already open).
1216
1217 Returns:
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001218 (payload_key, container_key, sign_tool):
Jooyung Han8caba5e2021-10-27 03:58:09 +09001219 - payload_key contains the path to the payload signing key
1220 - container_key contains the path to the container signing key
1221 - sign_tool is an apex-specific signing tool for its payload contents
Tao Baoaa7e9932019-03-15 09:37:01 -07001222 """
1223 keys = {}
Tao Baoa3705452019-06-24 15:33:41 -07001224 for line in tf_zip.read('META/apexkeys.txt').decode().split('\n'):
Tao Baoaa7e9932019-03-15 09:37:01 -07001225 line = line.strip()
1226 if not line:
1227 continue
1228 matches = re.match(
1229 r'^name="(?P<NAME>.*)"\s+'
1230 r'public_key="(?P<PAYLOAD_PUBLIC_KEY>.*)"\s+'
1231 r'private_key="(?P<PAYLOAD_PRIVATE_KEY>.*)"\s+'
1232 r'container_certificate="(?P<CONTAINER_CERT>.*)"\s+'
Bill Peckham5c7b0342020-04-03 15:36:23 -07001233 r'container_private_key="(?P<CONTAINER_PRIVATE_KEY>.*?)"'
Jooyung Han8caba5e2021-10-27 03:58:09 +09001234 r'(\s+partition="(?P<PARTITION>.*?)")?'
1235 r'(\s+sign_tool="(?P<SIGN_TOOL>.*?)")?$',
Tao Baoaa7e9932019-03-15 09:37:01 -07001236 line)
1237 if not matches:
1238 continue
1239
1240 name = matches.group('NAME')
Tao Baoaa7e9932019-03-15 09:37:01 -07001241 payload_private_key = matches.group("PAYLOAD_PRIVATE_KEY")
1242
1243 def CompareKeys(pubkey, pubkey_suffix, privkey, privkey_suffix):
1244 pubkey_suffix_len = len(pubkey_suffix)
1245 privkey_suffix_len = len(privkey_suffix)
1246 return (pubkey.endswith(pubkey_suffix) and
1247 privkey.endswith(privkey_suffix) and
1248 pubkey[:-pubkey_suffix_len] == privkey[:-privkey_suffix_len])
1249
Ivan Lozanob021b2a2020-07-28 09:31:06 -04001250 # Check the container key names, as we'll carry them without the
Tao Bao6d9e3da2019-03-26 12:59:25 -07001251 # extensions. This doesn't apply to payload keys though, which we will use
1252 # full names only.
Tao Baoaa7e9932019-03-15 09:37:01 -07001253 container_cert = matches.group("CONTAINER_CERT")
1254 container_private_key = matches.group("CONTAINER_PRIVATE_KEY")
Tao Baof454c3a2019-04-24 23:53:42 -07001255 if container_cert == 'PRESIGNED' and container_private_key == 'PRESIGNED':
1256 container_key = 'PRESIGNED'
1257 elif CompareKeys(
Kelvin Zhang7cab7502021-08-02 19:58:14 -04001258 container_cert, OPTIONS.public_key_suffix,
1259 container_private_key, OPTIONS.private_key_suffix):
Tao Baof454c3a2019-04-24 23:53:42 -07001260 container_key = container_cert[:-len(OPTIONS.public_key_suffix)]
1261 else:
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001262 raise ValueError("Failed to parse container keys: \n{}".format(line))
Tao Baoaa7e9932019-03-15 09:37:01 -07001263
Jooyung Han8caba5e2021-10-27 03:58:09 +09001264 sign_tool = matches.group("SIGN_TOOL")
1265 keys[name] = (payload_private_key, container_key, sign_tool)
Tao Baoaa7e9932019-03-15 09:37:01 -07001266
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001267 return keys
Tao Baoaa7e9932019-03-15 09:37:01 -07001268
1269
Daniel Norman78554ea2021-09-14 10:29:38 -07001270def BuildVendorPartitions(output_zip_path):
1271 """Builds OPTIONS.vendor_partitions using OPTIONS.vendor_otatools."""
1272 if OPTIONS.vendor_partitions.difference(ALLOWED_VENDOR_PARTITIONS):
1273 logger.warning("Allowed --vendor_partitions: %s",
1274 ",".join(ALLOWED_VENDOR_PARTITIONS))
1275 OPTIONS.vendor_partitions = ALLOWED_VENDOR_PARTITIONS.intersection(
1276 OPTIONS.vendor_partitions)
1277
1278 logger.info("Building vendor partitions using vendor otatools.")
1279 vendor_tempdir = common.UnzipTemp(output_zip_path, [
1280 "META/*",
Po Hu0663ae42021-09-27 12:59:06 +08001281 "SYSTEM/build.prop",
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001282 "RECOVERY/*",
1283 "BOOT/*",
1284 "OTA/",
Daniel Norman78554ea2021-09-14 10:29:38 -07001285 ] + ["{}/*".format(p.upper()) for p in OPTIONS.vendor_partitions])
1286
1287 # Disable various partitions that build based on misc_info fields.
1288 # Only partitions in ALLOWED_VENDOR_PARTITIONS can be rebuilt using
1289 # vendor otatools. These other partitions will be rebuilt using the main
1290 # otatools if necessary.
1291 vendor_misc_info_path = os.path.join(vendor_tempdir, "META/misc_info.txt")
1292 vendor_misc_info = common.LoadDictionaryFromFile(vendor_misc_info_path)
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001293 # Ignore if not rebuilding recovery
1294 if not OPTIONS.rebuild_recovery:
1295 vendor_misc_info["no_boot"] = "true" # boot
1296 vendor_misc_info["vendor_boot"] = "false" # vendor_boot
1297 vendor_misc_info["no_recovery"] = "true" # recovery
Iavor-Valentin Iftime40adb172022-04-19 18:17:56 +00001298 vendor_misc_info["avb_enable"] = "false" # vbmeta
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001299
Daniel Norman78554ea2021-09-14 10:29:38 -07001300 vendor_misc_info["board_bpt_enable"] = "false" # partition-table
1301 vendor_misc_info["has_dtbo"] = "false" # dtbo
1302 vendor_misc_info["has_pvmfw"] = "false" # pvmfw
1303 vendor_misc_info["avb_custom_images_partition_list"] = "" # custom images
Iavor-Valentin Iftime40adb172022-04-19 18:17:56 +00001304 vendor_misc_info["avb_building_vbmeta_image"] = "false" # skip building vbmeta
Daniel Norman78554ea2021-09-14 10:29:38 -07001305 vendor_misc_info["use_dynamic_partitions"] = "false" # super_empty
1306 vendor_misc_info["build_super_partition"] = "false" # super split
1307 with open(vendor_misc_info_path, "w") as output:
1308 for key in sorted(vendor_misc_info):
1309 output.write("{}={}\n".format(key, vendor_misc_info[key]))
1310
Po Hu0663ae42021-09-27 12:59:06 +08001311 # Disable system partition by a placeholder of IMAGES/system.img,
1312 # instead of removing SYSTEM folder.
1313 # Because SYSTEM/build.prop is still needed for:
1314 # add_img_to_target_files.CreateImage ->
1315 # common.BuildInfo ->
1316 # common.BuildInfo.CalculateFingerprint
1317 vendor_images_path = os.path.join(vendor_tempdir, "IMAGES")
1318 if not os.path.exists(vendor_images_path):
1319 os.makedirs(vendor_images_path)
1320 with open(os.path.join(vendor_images_path, "system.img"), "w") as output:
1321 pass
1322
Daniel Norman78554ea2021-09-14 10:29:38 -07001323 # Disable care_map.pb as not all ab_partitions are available when
1324 # vendor otatools regenerates vendor images.
Po Hu0663ae42021-09-27 12:59:06 +08001325 if os.path.exists(os.path.join(vendor_tempdir, "META/ab_partitions.txt")):
1326 os.remove(os.path.join(vendor_tempdir, "META/ab_partitions.txt"))
1327 # Disable RADIO images
1328 if os.path.exists(os.path.join(vendor_tempdir, "META/pack_radioimages.txt")):
1329 os.remove(os.path.join(vendor_tempdir, "META/pack_radioimages.txt"))
Daniel Norman78554ea2021-09-14 10:29:38 -07001330
1331 # Build vendor images using vendor otatools.
Iavor-Valentin Iftime63cde0f2022-03-04 16:02:44 +00001332 # Accept either a zip file or extracted directory.
1333 if os.path.isfile(OPTIONS.vendor_otatools):
1334 vendor_otatools_dir = common.MakeTempDir(prefix="vendor_otatools_")
1335 common.UnzipToDir(OPTIONS.vendor_otatools, vendor_otatools_dir)
1336 else:
1337 vendor_otatools_dir = OPTIONS.vendor_otatools
Daniel Norman78554ea2021-09-14 10:29:38 -07001338 cmd = [
1339 os.path.join(vendor_otatools_dir, "bin", "add_img_to_target_files"),
1340 "--is_signing",
Po Hu0663ae42021-09-27 12:59:06 +08001341 "--add_missing",
Daniel Norman78554ea2021-09-14 10:29:38 -07001342 "--verbose",
1343 vendor_tempdir,
1344 ]
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001345 if OPTIONS.rebuild_recovery:
1346 cmd.insert(4, "--rebuild_recovery")
1347
Daniel Norman78554ea2021-09-14 10:29:38 -07001348 common.RunAndCheckOutput(cmd, verbose=True)
1349
1350 logger.info("Writing vendor partitions to output archive.")
1351 with zipfile.ZipFile(
1352 output_zip_path, "a", compression=zipfile.ZIP_DEFLATED,
1353 allowZip64=True) as output_zip:
1354 for p in OPTIONS.vendor_partitions:
Iavor-Valentin Iftime880e4432022-03-17 14:02:27 +00001355 img_file_path = "IMAGES/{}.img".format(p)
1356 map_file_path = "IMAGES/{}.map".format(p)
1357 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, img_file_path), img_file_path)
1358 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, map_file_path), map_file_path)
Iavor-Valentin Iftime40adb172022-04-19 18:17:56 +00001359 # copy recovery.img, boot.img, recovery patch & install.sh
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001360 if OPTIONS.rebuild_recovery:
Iavor-Valentin Iftime40adb172022-04-19 18:17:56 +00001361 recovery_img = "IMAGES/recovery.img"
1362 boot_img = "IMAGES/boot.img"
1363 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, recovery_img), recovery_img)
1364 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, boot_img), boot_img)
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001365 recovery_patch_path = "VENDOR/recovery-from-boot.p"
1366 recovery_sh_path = "VENDOR/bin/install-recovery.sh"
1367 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, recovery_patch_path), recovery_patch_path)
1368 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, recovery_sh_path), recovery_sh_path)
Daniel Norman78554ea2021-09-14 10:29:38 -07001369
1370
Doug Zongkereef39442009-04-02 12:14:19 -07001371def main(argv):
1372
Doug Zongker831840e2011-09-22 10:28:04 -07001373 key_mapping_options = []
1374
Doug Zongkereef39442009-04-02 12:14:19 -07001375 def option_handler(o, a):
Doug Zongker05d3dea2009-06-22 11:32:31 -07001376 if o in ("-e", "--extra_apks"):
Doug Zongkereef39442009-04-02 12:14:19 -07001377 names, key = a.split("=")
1378 names = names.split(",")
1379 for n in names:
1380 OPTIONS.extra_apks[n] = key
Tao Baoaa7e9932019-03-15 09:37:01 -07001381 elif o == "--extra_apex_payload_key":
1382 apex_name, key = a.split("=")
1383 OPTIONS.extra_apex_payload_keys[apex_name] = key
Tao Bao93c2a012018-06-19 12:19:35 -07001384 elif o == "--skip_apks_with_path_prefix":
Tianjiea85bdf02020-07-29 11:56:19 -07001385 # Check the prefix, which must be in all upper case.
Tao Bao93c2a012018-06-19 12:19:35 -07001386 prefix = a.split('/')[0]
1387 if not prefix or prefix != prefix.upper():
1388 raise ValueError("Invalid path prefix '%s'" % (a,))
1389 OPTIONS.skip_apks_with_path_prefix.add(a)
Doug Zongkereef39442009-04-02 12:14:19 -07001390 elif o in ("-d", "--default_key_mappings"):
Doug Zongker831840e2011-09-22 10:28:04 -07001391 key_mapping_options.append((None, a))
Doug Zongkereef39442009-04-02 12:14:19 -07001392 elif o in ("-k", "--key_mapping"):
Doug Zongker831840e2011-09-22 10:28:04 -07001393 key_mapping_options.append(a.split("=", 1))
Doug Zongker8e931bf2009-04-06 15:21:45 -07001394 elif o in ("-o", "--replace_ota_keys"):
1395 OPTIONS.replace_ota_keys = True
Doug Zongkerae877012009-04-21 10:04:51 -07001396 elif o in ("-t", "--tag_changes"):
1397 new = []
1398 for i in a.split(","):
1399 i = i.strip()
1400 if not i or i[0] not in "-+":
1401 raise ValueError("Bad tag change '%s'" % (i,))
1402 new.append(i[0] + i[1:].strip())
1403 OPTIONS.tag_changes = tuple(new)
Geremy Condraf19b3652014-07-29 17:54:54 -07001404 elif o == "--replace_verity_public_key":
1405 OPTIONS.replace_verity_public_key = (True, a)
1406 elif o == "--replace_verity_private_key":
1407 OPTIONS.replace_verity_private_key = (True, a)
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001408 elif o == "--replace_verity_keyid":
1409 OPTIONS.replace_verity_keyid = (True, a)
Bowgo Tsai2fe786a2020-02-21 17:48:18 +08001410 elif o == "--remove_avb_public_keys":
1411 OPTIONS.remove_avb_public_keys = a.split(",")
Tao Bao639118f2017-06-19 15:48:02 -07001412 elif o == "--avb_vbmeta_key":
1413 OPTIONS.avb_keys['vbmeta'] = a
1414 elif o == "--avb_vbmeta_algorithm":
1415 OPTIONS.avb_algorithms['vbmeta'] = a
1416 elif o == "--avb_vbmeta_extra_args":
1417 OPTIONS.avb_extra_args['vbmeta'] = a
1418 elif o == "--avb_boot_key":
1419 OPTIONS.avb_keys['boot'] = a
1420 elif o == "--avb_boot_algorithm":
1421 OPTIONS.avb_algorithms['boot'] = a
1422 elif o == "--avb_boot_extra_args":
1423 OPTIONS.avb_extra_args['boot'] = a
1424 elif o == "--avb_dtbo_key":
1425 OPTIONS.avb_keys['dtbo'] = a
1426 elif o == "--avb_dtbo_algorithm":
1427 OPTIONS.avb_algorithms['dtbo'] = a
1428 elif o == "--avb_dtbo_extra_args":
1429 OPTIONS.avb_extra_args['dtbo'] = a
1430 elif o == "--avb_system_key":
1431 OPTIONS.avb_keys['system'] = a
1432 elif o == "--avb_system_algorithm":
1433 OPTIONS.avb_algorithms['system'] = a
1434 elif o == "--avb_system_extra_args":
1435 OPTIONS.avb_extra_args['system'] = a
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001436 elif o == "--avb_system_other_key":
1437 OPTIONS.avb_keys['system_other'] = a
1438 elif o == "--avb_system_other_algorithm":
1439 OPTIONS.avb_algorithms['system_other'] = a
1440 elif o == "--avb_system_other_extra_args":
1441 OPTIONS.avb_extra_args['system_other'] = a
Tao Bao639118f2017-06-19 15:48:02 -07001442 elif o == "--avb_vendor_key":
1443 OPTIONS.avb_keys['vendor'] = a
1444 elif o == "--avb_vendor_algorithm":
1445 OPTIONS.avb_algorithms['vendor'] = a
1446 elif o == "--avb_vendor_extra_args":
1447 OPTIONS.avb_extra_args['vendor'] = a
Tao Baod6085d62019-05-06 12:55:42 -07001448 elif o == "--avb_vbmeta_system_key":
1449 OPTIONS.avb_keys['vbmeta_system'] = a
1450 elif o == "--avb_vbmeta_system_algorithm":
1451 OPTIONS.avb_algorithms['vbmeta_system'] = a
1452 elif o == "--avb_vbmeta_system_extra_args":
1453 OPTIONS.avb_extra_args['vbmeta_system'] = a
1454 elif o == "--avb_vbmeta_vendor_key":
1455 OPTIONS.avb_keys['vbmeta_vendor'] = a
1456 elif o == "--avb_vbmeta_vendor_algorithm":
1457 OPTIONS.avb_algorithms['vbmeta_vendor'] = a
1458 elif o == "--avb_vbmeta_vendor_extra_args":
1459 OPTIONS.avb_extra_args['vbmeta_vendor'] = a
Tao Baoaa7e9932019-03-15 09:37:01 -07001460 elif o == "--avb_apex_extra_args":
1461 OPTIONS.avb_extra_args['apex'] = a
Hongguang Chenf23364d2020-04-27 18:36:36 -07001462 elif o == "--avb_extra_custom_image_key":
1463 partition, key = a.split("=")
1464 OPTIONS.avb_keys[partition] = key
1465 elif o == "--avb_extra_custom_image_algorithm":
1466 partition, algorithm = a.split("=")
1467 OPTIONS.avb_algorithms[partition] = algorithm
1468 elif o == "--avb_extra_custom_image_extra_args":
Hongguang Chen883eecb2020-05-23 22:20:19 -07001469 # Setting the maxsplit parameter to one, which will return a list with
1470 # two elements. e.g., the second '=' should not be splitted for
1471 # 'oem=--signing_helper_with_files=/tmp/avbsigner.sh'.
1472 partition, extra_args = a.split("=", 1)
Hongguang Chenf23364d2020-04-27 18:36:36 -07001473 OPTIONS.avb_extra_args[partition] = extra_args
Bowgo Tsai27c39b02021-03-12 21:40:32 +08001474 elif o == "--gki_signing_key":
1475 OPTIONS.gki_signing_key = a
1476 elif o == "--gki_signing_algorithm":
1477 OPTIONS.gki_signing_algorithm = a
1478 elif o == "--gki_signing_extra_args":
1479 OPTIONS.gki_signing_extra_args = a
Daniel Norman78554ea2021-09-14 10:29:38 -07001480 elif o == "--vendor_otatools":
1481 OPTIONS.vendor_otatools = a
1482 elif o == "--vendor_partitions":
1483 OPTIONS.vendor_partitions = set(a.split(","))
Bowgo Tsai2a781692021-10-13 17:39:33 +08001484 elif o == "--allow_gsi_debug_sepolicy":
1485 OPTIONS.allow_gsi_debug_sepolicy = True
Doug Zongkereef39442009-04-02 12:14:19 -07001486 else:
1487 return False
1488 return True
1489
Tao Bao639118f2017-06-19 15:48:02 -07001490 args = common.ParseOptions(
1491 argv, __doc__,
1492 extra_opts="e:d:k:ot:",
1493 extra_long_opts=[
Tao Bao0c28d2d2017-12-24 10:37:38 -08001494 "extra_apks=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001495 "extra_apex_payload_key=",
Tao Bao93c2a012018-06-19 12:19:35 -07001496 "skip_apks_with_path_prefix=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001497 "default_key_mappings=",
1498 "key_mapping=",
1499 "replace_ota_keys",
1500 "tag_changes=",
1501 "replace_verity_public_key=",
1502 "replace_verity_private_key=",
1503 "replace_verity_keyid=",
Bowgo Tsai2fe786a2020-02-21 17:48:18 +08001504 "remove_avb_public_keys=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001505 "avb_apex_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001506 "avb_vbmeta_algorithm=",
1507 "avb_vbmeta_key=",
1508 "avb_vbmeta_extra_args=",
1509 "avb_boot_algorithm=",
1510 "avb_boot_key=",
1511 "avb_boot_extra_args=",
1512 "avb_dtbo_algorithm=",
1513 "avb_dtbo_key=",
1514 "avb_dtbo_extra_args=",
1515 "avb_system_algorithm=",
1516 "avb_system_key=",
1517 "avb_system_extra_args=",
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001518 "avb_system_other_algorithm=",
1519 "avb_system_other_key=",
1520 "avb_system_other_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001521 "avb_vendor_algorithm=",
1522 "avb_vendor_key=",
1523 "avb_vendor_extra_args=",
Tao Baod6085d62019-05-06 12:55:42 -07001524 "avb_vbmeta_system_algorithm=",
1525 "avb_vbmeta_system_key=",
1526 "avb_vbmeta_system_extra_args=",
1527 "avb_vbmeta_vendor_algorithm=",
1528 "avb_vbmeta_vendor_key=",
1529 "avb_vbmeta_vendor_extra_args=",
Hongguang Chenf23364d2020-04-27 18:36:36 -07001530 "avb_extra_custom_image_key=",
1531 "avb_extra_custom_image_algorithm=",
1532 "avb_extra_custom_image_extra_args=",
Bowgo Tsai27c39b02021-03-12 21:40:32 +08001533 "gki_signing_key=",
1534 "gki_signing_algorithm=",
1535 "gki_signing_extra_args=",
Daniel Norman78554ea2021-09-14 10:29:38 -07001536 "vendor_partitions=",
1537 "vendor_otatools=",
Bowgo Tsai2a781692021-10-13 17:39:33 +08001538 "allow_gsi_debug_sepolicy",
Tao Bao639118f2017-06-19 15:48:02 -07001539 ],
1540 extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001541
1542 if len(args) != 2:
1543 common.Usage(__doc__)
1544 sys.exit(1)
1545
Tao Baobadceb22019-03-15 09:33:43 -07001546 common.InitLogging()
1547
Kelvin Zhang928c2342020-09-22 16:15:57 -04001548 input_zip = zipfile.ZipFile(args[0], "r", allowZip64=True)
Tao Bao2b8f4892017-06-13 12:54:58 -07001549 output_zip = zipfile.ZipFile(args[1], "w",
1550 compression=zipfile.ZIP_DEFLATED,
1551 allowZip64=True)
Doug Zongkereef39442009-04-02 12:14:19 -07001552
Doug Zongker831840e2011-09-22 10:28:04 -07001553 misc_info = common.LoadInfoDict(input_zip)
1554
1555 BuildKeyMap(misc_info, key_mapping_options)
1556
Tao Baoaa7e9932019-03-15 09:37:01 -07001557 apk_keys_info, compressed_extension = common.ReadApkCerts(input_zip)
1558 apk_keys = GetApkCerts(apk_keys_info)
Doug Zongkereb338ef2009-05-20 16:50:49 -07001559
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001560 apex_keys_info = ReadApexKeysInfo(input_zip)
Tao Baoaa7e9932019-03-15 09:37:01 -07001561 apex_keys = GetApexKeys(apex_keys_info, apk_keys)
1562
Tianjie Xu88a759d2020-01-23 10:47:54 -08001563 # TODO(xunchang) check for the apks inside the apex files, and abort early if
1564 # the keys are not available.
Tao Baoaa7e9932019-03-15 09:37:01 -07001565 CheckApkAndApexKeysAvailable(
1566 input_zip,
1567 set(apk_keys.keys()) | set(apex_keys.keys()),
Tao Baoe1343992019-03-19 12:24:03 -07001568 compressed_extension,
1569 apex_keys)
Tao Baoaa7e9932019-03-15 09:37:01 -07001570
1571 key_passwords = common.GetKeyPasswords(
1572 set(apk_keys.values()) | set(itertools.chain(*apex_keys.values())))
Tao Bao9aa4b9b2016-09-29 17:53:56 -07001573 platform_api_level, _ = GetApiLevelAndCodename(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001574 codename_to_api_level_map = GetCodenameToApiLevelMap(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001575
Doug Zongker412c02f2014-02-13 10:58:24 -08001576 ProcessTargetFiles(input_zip, output_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -07001577 apk_keys, apex_keys, key_passwords,
1578 platform_api_level, codename_to_api_level_map,
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001579 compressed_extension)
Doug Zongker8e931bf2009-04-06 15:21:45 -07001580
Tao Bao2ed665a2015-04-01 11:21:55 -07001581 common.ZipClose(input_zip)
1582 common.ZipClose(output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001583
Daniel Norman78554ea2021-09-14 10:29:38 -07001584 if OPTIONS.vendor_partitions and OPTIONS.vendor_otatools:
1585 BuildVendorPartitions(args[1])
1586
Tianjie Xub48589a2016-08-03 19:21:52 -07001587 # Skip building userdata.img and cache.img when signing the target files.
Daniel Norman78554ea2021-09-14 10:29:38 -07001588 new_args = ["--is_signing", "--add_missing", "--verbose"]
Tianjie Xu616fbeb2017-05-23 14:51:02 -07001589 # add_img_to_target_files builds the system image from scratch, so the
1590 # recovery patch is guaranteed to be regenerated there.
1591 if OPTIONS.rebuild_recovery:
1592 new_args.append("--rebuild_recovery")
1593 new_args.append(args[1])
Tianjie Xub48589a2016-08-03 19:21:52 -07001594 add_img_to_target_files.main(new_args)
Doug Zongker3c84f562014-07-31 11:06:30 -07001595
Tao Bao0c28d2d2017-12-24 10:37:38 -08001596 print("done.")
Doug Zongkereef39442009-04-02 12:14:19 -07001597
1598
1599if __name__ == '__main__':
1600 try:
1601 main(sys.argv[1:])
Tao Bao639118f2017-06-19 15:48:02 -07001602 finally:
1603 common.Cleanup()