blob: f363afd848b672ea0d31e64b1372a997fefece16 [file] [log] [blame]
Doug Zongkereef39442009-04-02 12:14:19 -07001#!/usr/bin/env python
2#
3# Copyright (C) 2008 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17"""
18Signs all the APK files in a target-files zipfile, producing a new
19target-files zip.
20
21Usage: sign_target_files_apks [flags] input_target_files output_target_files
22
Doug Zongkereef39442009-04-02 12:14:19 -070023 -e (--extra_apks) <name,name,...=key>
Tao Baoaa7e9932019-03-15 09:37:01 -070024 Add extra APK/APEX name/key pairs as though they appeared in apkcerts.txt
25 or apexkeys.txt (so mappings specified by -k and -d are applied). Keys
26 specified in -e override any value for that app contained in the
27 apkcerts.txt file, or the container key for an APEX. Option may be
28 repeated to give multiple extra packages.
29
30 --extra_apex_payload_key <name=key>
31 Add a mapping for APEX package name to payload signing key, which will
32 override the default payload signing key in apexkeys.txt. Note that the
33 container key should be overridden via the `--extra_apks` flag above.
34 Option may be repeated for multiple APEXes.
Doug Zongkereef39442009-04-02 12:14:19 -070035
Tao Bao93c2a012018-06-19 12:19:35 -070036 --skip_apks_with_path_prefix <prefix>
37 Skip signing an APK if it has the matching prefix in its path. The prefix
38 should be matching the entry name, which has partition names in upper
39 case, e.g. "VENDOR/app/", or "SYSTEM_OTHER/preloads/". Option may be
40 repeated to give multiple prefixes.
41
Doug Zongkereef39442009-04-02 12:14:19 -070042 -k (--key_mapping) <src_key=dest_key>
43 Add a mapping from the key name as specified in apkcerts.txt (the
44 src_key) to the real key you wish to sign the package with
45 (dest_key). Option may be repeated to give multiple key
46 mappings.
47
48 -d (--default_key_mappings) <dir>
49 Set up the following key mappings:
50
Doug Zongker831840e2011-09-22 10:28:04 -070051 $devkey/devkey ==> $dir/releasekey
52 $devkey/testkey ==> $dir/releasekey
53 $devkey/media ==> $dir/media
54 $devkey/shared ==> $dir/shared
55 $devkey/platform ==> $dir/platform
56
57 where $devkey is the directory part of the value of
58 default_system_dev_certificate from the input target-files's
Dan Willemsen0ab1be62019-04-09 21:35:37 -070059 META/misc_info.txt. (Defaulting to "build/make/target/product/security"
Doug Zongker831840e2011-09-22 10:28:04 -070060 if the value is not present in misc_info.
Doug Zongkereef39442009-04-02 12:14:19 -070061
62 -d and -k options are added to the set of mappings in the order
63 in which they appear on the command line.
Doug Zongker8e931bf2009-04-06 15:21:45 -070064
65 -o (--replace_ota_keys)
Tao Baoa80ed222016-06-16 14:41:24 -070066 Replace the certificate (public key) used by OTA package verification
67 with the ones specified in the input target_files zip (in the
68 META/otakeys.txt file). Key remapping (-k and -d) is performed on the
69 keys. For A/B devices, the payload verification key will be replaced
70 as well. If there're multiple OTA keys, only the first one will be used
71 for payload verification.
Doug Zongker17aa9442009-04-17 10:15:58 -070072
Doug Zongkerae877012009-04-21 10:04:51 -070073 -t (--tag_changes) <+tag>,<-tag>,...
74 Comma-separated list of changes to make to the set of tags (in
75 the last component of the build fingerprint). Prefix each with
76 '+' or '-' to indicate whether that tag should be added or
77 removed. Changes are processed in the order they appear.
Doug Zongker831840e2011-09-22 10:28:04 -070078 Default value is "-test-keys,-dev-keys,+release-keys".
Doug Zongkerae877012009-04-21 10:04:51 -070079
Tao Bao8adcfd12016-06-17 17:01:22 -070080 --replace_verity_private_key <key>
81 Replace the private key used for verity signing. It expects a filename
82 WITHOUT the extension (e.g. verity_key).
83
84 --replace_verity_public_key <key>
85 Replace the certificate (public key) used for verity verification. The
86 key file replaces the one at BOOT/RAMDISK/verity_key (or ROOT/verity_key
87 for devices using system_root_image). It expects the key filename WITH
88 the extension (e.g. verity_key.pub).
89
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -070090 --replace_verity_keyid <path_to_X509_PEM_cert_file>
91 Replace the veritykeyid in BOOT/cmdline of input_target_file_zip
Tao Bao8adcfd12016-06-17 17:01:22 -070092 with keyid of the cert pointed by <path_to_X509_PEM_cert_file>.
Tao Bao639118f2017-06-19 15:48:02 -070093
Bowgo Tsai2fe786a2020-02-21 17:48:18 +080094 --remove_avb_public_keys <key1>,<key2>,...
95 Remove AVB public keys from the first-stage ramdisk. The key file to
96 remove is located at either of the following dirs:
97 - BOOT/RAMDISK/avb/ or
98 - BOOT/RAMDISK/first_stage_ramdisk/avb/
99 The second dir will be used for lookup if BOARD_USES_RECOVERY_AS_BOOT is
100 set to true.
101
Tao Baod6085d62019-05-06 12:55:42 -0700102 --avb_{boot,system,system_other,vendor,dtbo,vbmeta,vbmeta_system,
103 vbmeta_vendor}_algorithm <algorithm>
104 --avb_{boot,system,system_other,vendor,dtbo,vbmeta,vbmeta_system,
105 vbmeta_vendor}_key <key>
Tao Bao639118f2017-06-19 15:48:02 -0700106 Use the specified algorithm (e.g. SHA256_RSA4096) and the key to AVB-sign
107 the specified image. Otherwise it uses the existing values in info dict.
108
Tao Baod6085d62019-05-06 12:55:42 -0700109 --avb_{apex,boot,system,system_other,vendor,dtbo,vbmeta,vbmeta_system,
110 vbmeta_vendor}_extra_args <args>
Tao Bao639118f2017-06-19 15:48:02 -0700111 Specify any additional args that are needed to AVB-sign the image
112 (e.g. "--signing_helper /path/to/helper"). The args will be appended to
113 the existing ones in info dict.
Tianjie Xu88a759d2020-01-23 10:47:54 -0800114
Hongguang Chenf23364d2020-04-27 18:36:36 -0700115 --avb_extra_custom_image_key <partition=key>
116 --avb_extra_custom_image_algorithm <partition=algorithm>
117 Use the specified algorithm (e.g. SHA256_RSA4096) and the key to AVB-sign
118 the specified custom images mounted on the partition. Otherwise it uses
119 the existing values in info dict.
120
121 --avb_extra_custom_image_extra_args <partition=extra_args>
122 Specify any additional args that are needed to AVB-sign the custom images
123 mounted on the partition (e.g. "--signing_helper /path/to/helper"). The
124 args will be appended to the existing ones in info dict.
125
Bowgo Tsai27c39b02021-03-12 21:40:32 +0800126 --gki_signing_algorithm <algorithm>
127 --gki_signing_key <key>
128 Use the specified algorithm (e.g. SHA256_RSA4096) and the key to generate
129 'boot signature' in a v4 boot.img. Otherwise it uses the existing values
130 in info dict.
131
132 --gki_signing_extra_args <args>
133 Specify any additional args that are needed to generate 'boot signature'
134 (e.g. --prop foo:bar). The args will be appended to the existing ones
135 in info dict.
136
Tianjie Xu88a759d2020-01-23 10:47:54 -0800137 --android_jar_path <path>
138 Path to the android.jar to repack the apex file.
Bowgo Tsai2a781692021-10-13 17:39:33 +0800139
Melisa Carranza Zunigae6d4fb52022-03-07 14:56:26 +0100140 --sepolicy_key <key>
141 Optional flag that specifies the sepolicy signing key, defaults to payload_key for the sepolicy.apex.
142
143 --sepolicy_cert <cert>
144 Optional flag that specifies the sepolicy signing cert.
145
146 --fsverity_tool <path>
147 Optional flag that specifies the path to fsverity tool to sign SEPolicy, defaults to fsverity.
148
Bowgo Tsai2a781692021-10-13 17:39:33 +0800149 --allow_gsi_debug_sepolicy
150 Allow the existence of the file 'userdebug_plat_sepolicy.cil' under
151 (/system/system_ext|/system_ext)/etc/selinux.
152 If not set, error out when the file exists.
Doug Zongkereef39442009-04-02 12:14:19 -0700153"""
154
Tao Bao0c28d2d2017-12-24 10:37:38 -0800155from __future__ import print_function
Doug Zongkereef39442009-04-02 12:14:19 -0700156
Robert Craig817c5742013-04-19 10:59:22 -0400157import base64
Doug Zongker8e931bf2009-04-06 15:21:45 -0700158import copy
Robert Craig817c5742013-04-19 10:59:22 -0400159import errno
Narayan Kamatha07bf042017-08-14 14:49:21 +0100160import gzip
Tao Baobb733882019-07-24 23:31:19 -0700161import io
Tao Baoaa7e9932019-03-15 09:37:01 -0700162import itertools
Tao Baobadceb22019-03-15 09:33:43 -0700163import logging
Doug Zongkereef39442009-04-02 12:14:19 -0700164import os
165import re
Narayan Kamatha07bf042017-08-14 14:49:21 +0100166import shutil
Tao Bao9fdd00f2017-07-12 11:57:05 -0700167import stat
Doug Zongkereef39442009-04-02 12:14:19 -0700168import subprocess
Tao Bao0c28d2d2017-12-24 10:37:38 -0800169import sys
Doug Zongkereef39442009-04-02 12:14:19 -0700170import tempfile
171import zipfile
Tao Bao66472632017-12-04 17:16:36 -0800172from xml.etree import ElementTree
Doug Zongkereef39442009-04-02 12:14:19 -0700173
Doug Zongker3c84f562014-07-31 11:06:30 -0700174import add_img_to_target_files
Tao Baoaa7e9932019-03-15 09:37:01 -0700175import apex_utils
Doug Zongkereef39442009-04-02 12:14:19 -0700176import common
177
Tao Bao0c28d2d2017-12-24 10:37:38 -0800178
179if sys.hexversion < 0x02070000:
180 print("Python 2.7 or newer is required.", file=sys.stderr)
181 sys.exit(1)
182
183
Tao Baobadceb22019-03-15 09:33:43 -0700184logger = logging.getLogger(__name__)
185
Doug Zongkereef39442009-04-02 12:14:19 -0700186OPTIONS = common.OPTIONS
187
188OPTIONS.extra_apks = {}
Tao Baoaa7e9932019-03-15 09:37:01 -0700189OPTIONS.extra_apex_payload_keys = {}
Tao Bao93c2a012018-06-19 12:19:35 -0700190OPTIONS.skip_apks_with_path_prefix = set()
Doug Zongkereef39442009-04-02 12:14:19 -0700191OPTIONS.key_map = {}
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700192OPTIONS.rebuild_recovery = False
Doug Zongker8e931bf2009-04-06 15:21:45 -0700193OPTIONS.replace_ota_keys = False
Geremy Condraf19b3652014-07-29 17:54:54 -0700194OPTIONS.replace_verity_public_key = False
195OPTIONS.replace_verity_private_key = False
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700196OPTIONS.replace_verity_keyid = False
Bowgo Tsai2fe786a2020-02-21 17:48:18 +0800197OPTIONS.remove_avb_public_keys = None
Doug Zongker831840e2011-09-22 10:28:04 -0700198OPTIONS.tag_changes = ("-test-keys", "-dev-keys", "+release-keys")
Tao Bao639118f2017-06-19 15:48:02 -0700199OPTIONS.avb_keys = {}
200OPTIONS.avb_algorithms = {}
201OPTIONS.avb_extra_args = {}
Bowgo Tsai27c39b02021-03-12 21:40:32 +0800202OPTIONS.gki_signing_key = None
203OPTIONS.gki_signing_algorithm = None
204OPTIONS.gki_signing_extra_args = None
Tianjie Xu88a759d2020-01-23 10:47:54 -0800205OPTIONS.android_jar_path = None
Daniel Norman78554ea2021-09-14 10:29:38 -0700206OPTIONS.vendor_partitions = set()
207OPTIONS.vendor_otatools = None
Melisa Carranza Zunigae6d4fb52022-03-07 14:56:26 +0100208OPTIONS.sepolicy_key = None
209OPTIONS.sepolicy_cert = None
210OPTIONS.fsverity_tool = None
Bowgo Tsai2a781692021-10-13 17:39:33 +0800211OPTIONS.allow_gsi_debug_sepolicy = False
Doug Zongkereef39442009-04-02 12:14:19 -0700212
Tao Bao0c28d2d2017-12-24 10:37:38 -0800213
Tao Bao19b02fe2019-10-09 00:04:28 -0700214AVB_FOOTER_ARGS_BY_PARTITION = {
Tianjiebf0b8a82021-03-03 17:31:04 -0800215 'boot': 'avb_boot_add_hash_footer_args',
Devin Mooreafdd7c72021-12-13 22:04:08 +0000216 'init_boot': 'avb_init_boot_add_hash_footer_args',
Tianjiebf0b8a82021-03-03 17:31:04 -0800217 'dtbo': 'avb_dtbo_add_hash_footer_args',
218 'product': 'avb_product_add_hashtree_footer_args',
219 'recovery': 'avb_recovery_add_hash_footer_args',
220 'system': 'avb_system_add_hashtree_footer_args',
Ramji Jiyani13a41372022-01-27 07:05:08 +0000221 'system_dlkm': "avb_system_dlkm_add_hashtree_footer_args",
Tianjiebf0b8a82021-03-03 17:31:04 -0800222 'system_ext': 'avb_system_ext_add_hashtree_footer_args',
223 'system_other': 'avb_system_other_add_hashtree_footer_args',
224 'odm': 'avb_odm_add_hashtree_footer_args',
225 'odm_dlkm': 'avb_odm_dlkm_add_hashtree_footer_args',
226 'pvmfw': 'avb_pvmfw_add_hash_footer_args',
227 'vendor': 'avb_vendor_add_hashtree_footer_args',
228 'vendor_boot': 'avb_vendor_boot_add_hash_footer_args',
Lucas Wei03230252022-04-18 16:00:40 +0800229 'vendor_kernel_boot': 'avb_vendor_kernel_boot_add_hash_footer_args',
Tianjiebf0b8a82021-03-03 17:31:04 -0800230 'vendor_dlkm': "avb_vendor_dlkm_add_hashtree_footer_args",
231 'vbmeta': 'avb_vbmeta_args',
232 'vbmeta_system': 'avb_vbmeta_system_args',
233 'vbmeta_vendor': 'avb_vbmeta_vendor_args',
Tao Bao19b02fe2019-10-09 00:04:28 -0700234}
235
236
Tianjiebf0b8a82021-03-03 17:31:04 -0800237# Check that AVB_FOOTER_ARGS_BY_PARTITION is in sync with AVB_PARTITIONS.
238for partition in common.AVB_PARTITIONS:
239 if partition not in AVB_FOOTER_ARGS_BY_PARTITION:
240 raise RuntimeError("Missing {} in AVB_FOOTER_ARGS".format(partition))
241
Daniel Norman78554ea2021-09-14 10:29:38 -0700242# Partitions that can be regenerated after signing using a separate
243# vendor otatools package.
244ALLOWED_VENDOR_PARTITIONS = set(["vendor", "odm"])
245
Tianjiebf0b8a82021-03-03 17:31:04 -0800246
Tianjie4d48d502021-06-11 17:03:43 -0700247def IsApexFile(filename):
248 return filename.endswith(".apex") or filename.endswith(".capex")
249
Melisa Carranza Zunigae6d4fb52022-03-07 14:56:26 +0100250def IsSepolicyApex(filename):
251 return filename.endswith(OPTIONS.sepolicy_name)
Tianjie4d48d502021-06-11 17:03:43 -0700252
253def GetApexFilename(filename):
254 name = os.path.basename(filename)
255 # Replace the suffix for compressed apex
256 if name.endswith(".capex"):
257 return name.replace(".capex", ".apex")
258 return name
259
260
Narayan Kamatha07bf042017-08-14 14:49:21 +0100261def GetApkCerts(certmap):
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800262 # apply the key remapping to the contents of the file
Tao Baoa3705452019-06-24 15:33:41 -0700263 for apk, cert in certmap.items():
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800264 certmap[apk] = OPTIONS.key_map.get(cert, cert)
265
266 # apply all the -e options, overriding anything in the file
Tao Baoa3705452019-06-24 15:33:41 -0700267 for apk, cert in OPTIONS.extra_apks.items():
Doug Zongkerdecf9952009-12-15 17:27:49 -0800268 if not cert:
269 cert = "PRESIGNED"
Doug Zongkerad88c7c2009-04-14 12:34:27 -0700270 certmap[apk] = OPTIONS.key_map.get(cert, cert)
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800271
Doug Zongkereef39442009-04-02 12:14:19 -0700272 return certmap
273
Melisa Carranza Zunigae6d4fb52022-03-07 14:56:26 +0100274def GetSepolicyKeys(keys_info):
275 """Gets SEPolicy signing keys applying overrides from command line options.
276
277 Args:
278 keys_info: A dict that maps from the SEPolicy APEX filename to a tuple of
279 (sepolicy_key, sepolicy_cert, fsverity_tool).
280
281 Returns:
282 A dict that contains the updated APEX key mapping, which should be used for
283 the current signing.
284 """
285 for name in keys_info:
286 (sepolicy_key, sepolicy_cert, fsverity_tool) = keys_info[name]
287 sepolicy_key = OPTIONS.sepolicy_key if OPTIONS.sepolicy_key else sepolicy_key
288 sepolicy_cert = OPTIONS.sepolicy_cert if OPTIONS.sepolicy_cert else sepolicy_cert
289 fsverity_tool = OPTIONS.fsverity_tool if OPTIONS.fsverity_tool else fsverity_tool
290 keys_info[name] = (sepolicy_key, sepolicy_cert, fsverity_tool)
291 return keys_info
Doug Zongkereef39442009-04-02 12:14:19 -0700292
Tao Baoaa7e9932019-03-15 09:37:01 -0700293def GetApexKeys(keys_info, key_map):
294 """Gets APEX payload and container signing keys by applying the mapping rules.
295
Tao Baoe1343992019-03-19 12:24:03 -0700296 Presigned payload / container keys will be set accordingly.
Tao Baoaa7e9932019-03-15 09:37:01 -0700297
298 Args:
299 keys_info: A dict that maps from APEX filenames to a tuple of (payload_key,
Jooyung Han8caba5e2021-10-27 03:58:09 +0900300 container_key, sign_tool).
Tao Baoaa7e9932019-03-15 09:37:01 -0700301 key_map: A dict that overrides the keys, specified via command-line input.
302
303 Returns:
304 A dict that contains the updated APEX key mapping, which should be used for
305 the current signing.
Tao Baof98fa102019-04-24 14:51:25 -0700306
307 Raises:
308 AssertionError: On invalid container / payload key overrides.
Tao Baoaa7e9932019-03-15 09:37:01 -0700309 """
310 # Apply all the --extra_apex_payload_key options to override the payload
311 # signing keys in the given keys_info.
312 for apex, key in OPTIONS.extra_apex_payload_keys.items():
Tao Baoe1343992019-03-19 12:24:03 -0700313 if not key:
314 key = 'PRESIGNED'
Tao Bao34223092019-07-11 11:52:52 -0700315 if apex not in keys_info:
316 logger.warning('Failed to find %s in target_files; Ignored', apex)
317 continue
Jooyung Han8caba5e2021-10-27 03:58:09 +0900318 keys_info[apex] = (key, keys_info[apex][1], keys_info[apex][2])
Tao Baoaa7e9932019-03-15 09:37:01 -0700319
320 # Apply the key remapping to container keys.
Jooyung Han8caba5e2021-10-27 03:58:09 +0900321 for apex, (payload_key, container_key, sign_tool) in keys_info.items():
322 keys_info[apex] = (payload_key, key_map.get(container_key, container_key), sign_tool)
Tao Baoaa7e9932019-03-15 09:37:01 -0700323
324 # Apply all the --extra_apks options to override the container keys.
325 for apex, key in OPTIONS.extra_apks.items():
326 # Skip non-APEX containers.
327 if apex not in keys_info:
328 continue
Tao Baoe1343992019-03-19 12:24:03 -0700329 if not key:
330 key = 'PRESIGNED'
Jooyung Han8caba5e2021-10-27 03:58:09 +0900331 keys_info[apex] = (keys_info[apex][0], key_map.get(key, key), keys_info[apex][2])
Tao Baoaa7e9932019-03-15 09:37:01 -0700332
Tao Baof98fa102019-04-24 14:51:25 -0700333 # A PRESIGNED container entails a PRESIGNED payload. Apply this to all the
334 # APEX key pairs. However, a PRESIGNED container with non-PRESIGNED payload
335 # (overridden via commandline) indicates a config error, which should not be
336 # allowed.
Jooyung Han8caba5e2021-10-27 03:58:09 +0900337 for apex, (payload_key, container_key, sign_tool) in keys_info.items():
Tao Baof98fa102019-04-24 14:51:25 -0700338 if container_key != 'PRESIGNED':
339 continue
340 if apex in OPTIONS.extra_apex_payload_keys:
341 payload_override = OPTIONS.extra_apex_payload_keys[apex]
342 assert payload_override == '', \
343 ("Invalid APEX key overrides: {} has PRESIGNED container but "
344 "non-PRESIGNED payload key {}").format(apex, payload_override)
345 if payload_key != 'PRESIGNED':
346 print(
347 "Setting {} payload as PRESIGNED due to PRESIGNED container".format(
348 apex))
Jooyung Han8caba5e2021-10-27 03:58:09 +0900349 keys_info[apex] = ('PRESIGNED', 'PRESIGNED', None)
Tao Baof98fa102019-04-24 14:51:25 -0700350
Tao Baoaa7e9932019-03-15 09:37:01 -0700351 return keys_info
352
353
Tao Bao93c2a012018-06-19 12:19:35 -0700354def GetApkFileInfo(filename, compressed_extension, skipped_prefixes):
Tao Bao11f955c2018-06-19 12:19:35 -0700355 """Returns the APK info based on the given filename.
356
357 Checks if the given filename (with path) looks like an APK file, by taking the
Tao Bao93c2a012018-06-19 12:19:35 -0700358 compressed extension into consideration. If it appears to be an APK file,
359 further checks if the APK file should be skipped when signing, based on the
360 given path prefixes.
Tao Bao11f955c2018-06-19 12:19:35 -0700361
362 Args:
363 filename: Path to the file.
364 compressed_extension: The extension string of compressed APKs (e.g. ".gz"),
365 or None if there's no compressed APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700366 skipped_prefixes: A set/list/tuple of the path prefixes to be skipped.
Tao Bao11f955c2018-06-19 12:19:35 -0700367
368 Returns:
Tao Bao93c2a012018-06-19 12:19:35 -0700369 (is_apk, is_compressed, should_be_skipped): is_apk indicates whether the
370 given filename is an APK file. is_compressed indicates whether the APK file
371 is compressed (only meaningful when is_apk is True). should_be_skipped
372 indicates whether the filename matches any of the given prefixes to be
373 skipped.
Tao Bao11f955c2018-06-19 12:19:35 -0700374
375 Raises:
Tao Bao93c2a012018-06-19 12:19:35 -0700376 AssertionError: On invalid compressed_extension or skipped_prefixes inputs.
Tao Bao11f955c2018-06-19 12:19:35 -0700377 """
378 assert compressed_extension is None or compressed_extension.startswith('.'), \
379 "Invalid compressed_extension arg: '{}'".format(compressed_extension)
380
Tao Bao93c2a012018-06-19 12:19:35 -0700381 # skipped_prefixes should be one of set/list/tuple types. Other types such as
382 # str shouldn't be accepted.
Tao Baobadceb22019-03-15 09:33:43 -0700383 assert isinstance(skipped_prefixes, (set, list, tuple)), \
384 "Invalid skipped_prefixes input type: {}".format(type(skipped_prefixes))
Tao Bao93c2a012018-06-19 12:19:35 -0700385
Tao Bao11f955c2018-06-19 12:19:35 -0700386 compressed_apk_extension = (
387 ".apk" + compressed_extension if compressed_extension else None)
388 is_apk = (filename.endswith(".apk") or
389 (compressed_apk_extension and
390 filename.endswith(compressed_apk_extension)))
391 if not is_apk:
Tao Bao93c2a012018-06-19 12:19:35 -0700392 return (False, False, False)
Tao Bao11f955c2018-06-19 12:19:35 -0700393
394 is_compressed = (compressed_apk_extension and
395 filename.endswith(compressed_apk_extension))
Tao Bao93c2a012018-06-19 12:19:35 -0700396 should_be_skipped = filename.startswith(tuple(skipped_prefixes))
397 return (True, is_compressed, should_be_skipped)
Tao Bao11f955c2018-06-19 12:19:35 -0700398
399
Tao Baoaa7e9932019-03-15 09:37:01 -0700400def CheckApkAndApexKeysAvailable(input_tf_zip, known_keys,
Tao Baoe1343992019-03-19 12:24:03 -0700401 compressed_extension, apex_keys):
Tao Baoaa7e9932019-03-15 09:37:01 -0700402 """Checks that all the APKs and APEXes have keys specified.
Tao Bao11f955c2018-06-19 12:19:35 -0700403
404 Args:
405 input_tf_zip: An open target_files zip file.
Tao Baoaa7e9932019-03-15 09:37:01 -0700406 known_keys: A set of APKs and APEXes that have known signing keys.
Tao Bao11f955c2018-06-19 12:19:35 -0700407 compressed_extension: The extension string of compressed APKs, such as
Tao Baoaa7e9932019-03-15 09:37:01 -0700408 '.gz', or None if there's no compressed APKs.
Tao Baoe1343992019-03-19 12:24:03 -0700409 apex_keys: A dict that contains the key mapping from APEX name to
Jooyung Han8caba5e2021-10-27 03:58:09 +0900410 (payload_key, container_key, sign_tool).
Tao Bao11f955c2018-06-19 12:19:35 -0700411
412 Raises:
Tao Baoaa7e9932019-03-15 09:37:01 -0700413 AssertionError: On finding unknown APKs and APEXes.
Tao Bao11f955c2018-06-19 12:19:35 -0700414 """
Tao Baoaa7e9932019-03-15 09:37:01 -0700415 unknown_files = []
Doug Zongkereb338ef2009-05-20 16:50:49 -0700416 for info in input_tf_zip.infolist():
Tianjie5bd03952021-02-18 23:02:36 -0800417 # Handle APEXes on all partitions
Tianjie4d48d502021-06-11 17:03:43 -0700418 if IsApexFile(info.filename):
419 name = GetApexFilename(info.filename)
Tao Baoaa7e9932019-03-15 09:37:01 -0700420 if name not in known_keys:
421 unknown_files.append(name)
422 continue
423
424 # And APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700425 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
426 info.filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
427 if not is_apk or should_be_skipped:
Tao Bao11f955c2018-06-19 12:19:35 -0700428 continue
Tao Baoaa7e9932019-03-15 09:37:01 -0700429
Tao Bao11f955c2018-06-19 12:19:35 -0700430 name = os.path.basename(info.filename)
431 if is_compressed:
432 name = name[:-len(compressed_extension)]
Tao Baoaa7e9932019-03-15 09:37:01 -0700433 if name not in known_keys:
434 unknown_files.append(name)
Tao Bao11f955c2018-06-19 12:19:35 -0700435
Tao Baoaa7e9932019-03-15 09:37:01 -0700436 assert not unknown_files, \
Tao Bao11f955c2018-06-19 12:19:35 -0700437 ("No key specified for:\n {}\n"
438 "Use '-e <apkname>=' to specify a key (which may be an empty string to "
Tao Baoaa7e9932019-03-15 09:37:01 -0700439 "not sign this apk).".format("\n ".join(unknown_files)))
Doug Zongkereb338ef2009-05-20 16:50:49 -0700440
Tao Baoe1343992019-03-19 12:24:03 -0700441 # For all the APEXes, double check that we won't have an APEX that has only
Tao Baof98fa102019-04-24 14:51:25 -0700442 # one of the payload / container keys set. Note that non-PRESIGNED container
443 # with PRESIGNED payload could be allowed but currently unsupported. It would
444 # require changing SignApex implementation.
Tao Baoe1343992019-03-19 12:24:03 -0700445 if not apex_keys:
446 return
447
448 invalid_apexes = []
449 for info in input_tf_zip.infolist():
Tianjie4d48d502021-06-11 17:03:43 -0700450 if not IsApexFile(info.filename):
Tao Baoe1343992019-03-19 12:24:03 -0700451 continue
452
Tianjie4d48d502021-06-11 17:03:43 -0700453 name = GetApexFilename(info.filename)
454
Jooyung Han8caba5e2021-10-27 03:58:09 +0900455 (payload_key, container_key, _) = apex_keys[name]
Tao Baoe1343992019-03-19 12:24:03 -0700456 if ((payload_key in common.SPECIAL_CERT_STRINGS and
457 container_key not in common.SPECIAL_CERT_STRINGS) or
458 (payload_key not in common.SPECIAL_CERT_STRINGS and
459 container_key in common.SPECIAL_CERT_STRINGS)):
460 invalid_apexes.append(
461 "{}: payload_key {}, container_key {}".format(
462 name, payload_key, container_key))
463
464 assert not invalid_apexes, \
465 "Invalid APEX keys specified:\n {}\n".format(
466 "\n ".join(invalid_apexes))
467
Doug Zongkereb338ef2009-05-20 16:50:49 -0700468
Narayan Kamatha07bf042017-08-14 14:49:21 +0100469def SignApk(data, keyname, pw, platform_api_level, codename_to_api_level_map,
Oleg Aravin8046cb02020-06-02 16:02:38 -0700470 is_compressed, apk_name):
471 unsigned = tempfile.NamedTemporaryFile(suffix='_' + apk_name)
Doug Zongkereef39442009-04-02 12:14:19 -0700472 unsigned.write(data)
473 unsigned.flush()
474
Narayan Kamatha07bf042017-08-14 14:49:21 +0100475 if is_compressed:
476 uncompressed = tempfile.NamedTemporaryFile()
Tao Bao0c28d2d2017-12-24 10:37:38 -0800477 with gzip.open(unsigned.name, "rb") as in_file, \
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400478 open(uncompressed.name, "wb") as out_file:
Narayan Kamatha07bf042017-08-14 14:49:21 +0100479 shutil.copyfileobj(in_file, out_file)
480
481 # Finally, close the "unsigned" file (which is gzip compressed), and then
482 # replace it with the uncompressed version.
483 #
484 # TODO(narayan): All this nastiness can be avoided if python 3.2 is in use,
485 # we could just gzip / gunzip in-memory buffers instead.
486 unsigned.close()
487 unsigned = uncompressed
488
Oleg Aravin8046cb02020-06-02 16:02:38 -0700489 signed = tempfile.NamedTemporaryFile(suffix='_' + apk_name)
Doug Zongkereef39442009-04-02 12:14:19 -0700490
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800491 # For pre-N builds, don't upgrade to SHA-256 JAR signatures based on the APK's
492 # minSdkVersion to avoid increasing incremental OTA update sizes. If an APK
493 # didn't change, we don't want its signature to change due to the switch
494 # from SHA-1 to SHA-256.
495 # By default, APK signer chooses SHA-256 signatures if the APK's minSdkVersion
496 # is 18 or higher. For pre-N builds we disable this mechanism by pretending
497 # that the APK's minSdkVersion is 1.
498 # For N+ builds, we let APK signer rely on the APK's minSdkVersion to
499 # determine whether to use SHA-256.
500 min_api_level = None
501 if platform_api_level > 23:
502 # Let APK signer choose whether to use SHA-1 or SHA-256, based on the APK's
503 # minSdkVersion attribute
504 min_api_level = None
505 else:
506 # Force APK signer to use SHA-1
507 min_api_level = 1
508
509 common.SignFile(unsigned.name, signed.name, keyname, pw,
Tao Bao0c28d2d2017-12-24 10:37:38 -0800510 min_api_level=min_api_level,
511 codename_to_api_level_map=codename_to_api_level_map)
Doug Zongkereef39442009-04-02 12:14:19 -0700512
Tao Bao0c28d2d2017-12-24 10:37:38 -0800513 data = None
Narayan Kamatha07bf042017-08-14 14:49:21 +0100514 if is_compressed:
515 # Recompress the file after it has been signed.
516 compressed = tempfile.NamedTemporaryFile()
Tao Bao0c28d2d2017-12-24 10:37:38 -0800517 with open(signed.name, "rb") as in_file, \
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400518 gzip.open(compressed.name, "wb") as out_file:
Narayan Kamatha07bf042017-08-14 14:49:21 +0100519 shutil.copyfileobj(in_file, out_file)
520
521 data = compressed.read()
522 compressed.close()
523 else:
524 data = signed.read()
525
Doug Zongkereef39442009-04-02 12:14:19 -0700526 unsigned.close()
527 signed.close()
528
529 return data
530
Tianjie5bd03952021-02-18 23:02:36 -0800531
Kelvin Zhang119f2792021-02-10 12:45:24 -0500532def IsBuildPropFile(filename):
533 return filename in (
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400534 "SYSTEM/etc/prop.default",
535 "BOOT/RAMDISK/prop.default",
536 "RECOVERY/RAMDISK/prop.default",
Kelvin Zhang119f2792021-02-10 12:45:24 -0500537
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400538 "VENDOR_BOOT/RAMDISK/default.prop",
539 "VENDOR_BOOT/RAMDISK/prop.default",
Kelvin Zhang119f2792021-02-10 12:45:24 -0500540
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400541 # ROOT/default.prop is a legacy path, but may still exist for upgrading
542 # devices that don't support `property_overrides_split_enabled`.
543 "ROOT/default.prop",
Kelvin Zhang119f2792021-02-10 12:45:24 -0500544
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400545 # RECOVERY/RAMDISK/default.prop is a legacy path, but will always exist
546 # as a symlink in the current code. So it's a no-op here. Keeping the
547 # path here for clarity.
548 "RECOVERY/RAMDISK/default.prop") or filename.endswith("build.prop")
Doug Zongkereef39442009-04-02 12:14:19 -0700549
Tianjie5bd03952021-02-18 23:02:36 -0800550
Doug Zongker412c02f2014-02-13 10:58:24 -0800551def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -0700552 apk_keys, apex_keys, key_passwords,
553 platform_api_level, codename_to_api_level_map,
Melisa Carranza Zunigae6d4fb52022-03-07 14:56:26 +0100554 compressed_extension, sepolicy_keys):
Tao Bao93c2a012018-06-19 12:19:35 -0700555 # maxsize measures the maximum filename length, including the ones to be
556 # skipped.
Bowgo Tsai8d4b7242022-01-04 15:15:35 +0800557 try:
558 maxsize = max(
559 [len(os.path.basename(i.filename)) for i in input_tf_zip.infolist()
560 if GetApkFileInfo(i.filename, compressed_extension, [])[0]])
561 except ValueError:
562 # Sets this to zero for targets without APK files, e.g., gki_arm64.
563 maxsize = 0
564
Tao Baoa80ed222016-06-16 14:41:24 -0700565 system_root_image = misc_info.get("system_root_image") == "true"
Doug Zongker412c02f2014-02-13 10:58:24 -0800566
Doug Zongkereef39442009-04-02 12:14:19 -0700567 for info in input_tf_zip.infolist():
Tao Bao11f955c2018-06-19 12:19:35 -0700568 filename = info.filename
569 if filename.startswith("IMAGES/"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700570 continue
Doug Zongker3c84f562014-07-31 11:06:30 -0700571
Tao Bao04808502019-07-25 23:11:41 -0700572 # Skip OTA-specific images (e.g. split super images), which will be
573 # re-generated during signing.
Tao Bao33bf2682019-01-11 12:37:35 -0800574 if filename.startswith("OTA/") and filename.endswith(".img"):
575 continue
576
Tao Bao11f955c2018-06-19 12:19:35 -0700577 data = input_tf_zip.read(filename)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700578 out_info = copy.copy(info)
Tao Bao93c2a012018-06-19 12:19:35 -0700579 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
580 filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
581
582 if is_apk and should_be_skipped:
583 # Copy skipped APKs verbatim.
584 print(
585 "NOT signing: %s\n"
586 " (skipped due to matching prefix)" % (filename,))
587 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker412c02f2014-02-13 10:58:24 -0800588
Tao Baof2cffbd2015-07-22 12:33:18 -0700589 # Sign APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700590 elif is_apk:
Tao Bao11f955c2018-06-19 12:19:35 -0700591 name = os.path.basename(filename)
Narayan Kamatha07bf042017-08-14 14:49:21 +0100592 if is_compressed:
593 name = name[:-len(compressed_extension)]
594
Tao Baoaa7e9932019-03-15 09:37:01 -0700595 key = apk_keys[name]
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800596 if key not in common.SPECIAL_CERT_STRINGS:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800597 print(" signing: %-*s (%s)" % (maxsize, name, key))
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800598 signed_data = SignApk(data, key, key_passwords[key], platform_api_level,
Oleg Aravin8046cb02020-06-02 16:02:38 -0700599 codename_to_api_level_map, is_compressed, name)
Tao Bao2ed665a2015-04-01 11:21:55 -0700600 common.ZipWriteStr(output_tf_zip, out_info, signed_data)
Doug Zongkereef39442009-04-02 12:14:19 -0700601 else:
602 # an APK we're not supposed to sign.
Tao Bao93c2a012018-06-19 12:19:35 -0700603 print(
604 "NOT signing: %s\n"
605 " (skipped due to special cert string)" % (name,))
Tao Bao2ed665a2015-04-01 11:21:55 -0700606 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoa80ed222016-06-16 14:41:24 -0700607
Tianjie5bd03952021-02-18 23:02:36 -0800608 # Sign bundled APEX files on all partitions
Tianjie4d48d502021-06-11 17:03:43 -0700609 elif IsApexFile(filename):
610 name = GetApexFilename(filename)
611
Jooyung Han8caba5e2021-10-27 03:58:09 +0900612 payload_key, container_key, sign_tool = apex_keys[name]
Tao Baoaa7e9932019-03-15 09:37:01 -0700613
Tao Baoe1343992019-03-19 12:24:03 -0700614 # We've asserted not having a case with only one of them PRESIGNED.
615 if (payload_key not in common.SPECIAL_CERT_STRINGS and
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400616 container_key not in common.SPECIAL_CERT_STRINGS):
Tao Baoe1343992019-03-19 12:24:03 -0700617 print(" signing: %-*s container (%s)" % (
618 maxsize, name, container_key))
619 print(" : %-*s payload (%s)" % (
620 maxsize, name, payload_key))
Tao Baoaa7e9932019-03-15 09:37:01 -0700621
Melisa Carranza Zunigae6d4fb52022-03-07 14:56:26 +0100622 sepolicy_key = None
623 sepolicy_cert = None
624 fsverity_tool = None
625
626 if IsSepolicyApex(name):
627 (sepolicy_key, sepolicy_cert, fsverity_tool) = sepolicy_keys[name]
628 print(" : %-*s sepolicy key (%s)" % (
629 maxsize, name, sepolicy_key))
630 print(" : %-*s sepolicy cert (%s)" % (
631 maxsize, name, sepolicy_cert))
632
Tao Baoe7354ba2019-05-09 16:54:15 -0700633 signed_apex = apex_utils.SignApex(
Tao Bao1ac886e2019-06-26 11:58:22 -0700634 misc_info['avb_avbtool'],
Tao Baoe1343992019-03-19 12:24:03 -0700635 data,
636 payload_key,
637 container_key,
Oleh Cherpake555ab12020-10-05 17:04:59 +0300638 key_passwords,
Tianjie Xu88a759d2020-01-23 10:47:54 -0800639 apk_keys,
Tao Baoe1343992019-03-19 12:24:03 -0700640 codename_to_api_level_map,
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400641 no_hashtree=None, # Let apex_util determine if hash tree is needed
Jooyung Han8caba5e2021-10-27 03:58:09 +0900642 signing_args=OPTIONS.avb_extra_args.get('apex'),
Melisa Carranza Zunigae6d4fb52022-03-07 14:56:26 +0100643 sign_tool=sign_tool,
644 is_sepolicy=IsSepolicyApex(name),
645 sepolicy_key=sepolicy_key,
646 sepolicy_cert=sepolicy_cert,
647 fsverity_tool=fsverity_tool)
Tao Baoe1343992019-03-19 12:24:03 -0700648 common.ZipWrite(output_tf_zip, signed_apex, filename)
Tao Baoaa7e9932019-03-15 09:37:01 -0700649
Tao Baoe1343992019-03-19 12:24:03 -0700650 else:
651 print(
652 "NOT signing: %s\n"
653 " (skipped due to special cert string)" % (name,))
654 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoaa7e9932019-03-15 09:37:01 -0700655
Tao Baoa80ed222016-06-16 14:41:24 -0700656 # System properties.
Kelvin Zhang119f2792021-02-10 12:45:24 -0500657 elif IsBuildPropFile(filename):
Tao Bao11f955c2018-06-19 12:19:35 -0700658 print("Rewriting %s:" % (filename,))
Hung-ying Tyan7eb6a922017-05-01 21:56:26 +0800659 if stat.S_ISLNK(info.external_attr >> 16):
660 new_data = data
661 else:
Tao Baoa3705452019-06-24 15:33:41 -0700662 new_data = RewriteProps(data.decode())
Tao Bao2ed665a2015-04-01 11:21:55 -0700663 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700664
Tao Bao66472632017-12-04 17:16:36 -0800665 # Replace the certs in *mac_permissions.xml (there could be multiple, such
Inseob Kime7b222a2021-12-21 15:57:03 +0900666 # as {system,vendor}/etc/selinux/{plat,vendor}_mac_permissions.xml).
Tao Bao11f955c2018-06-19 12:19:35 -0700667 elif filename.endswith("mac_permissions.xml"):
668 print("Rewriting %s with new keys." % (filename,))
Tao Baoa3705452019-06-24 15:33:41 -0700669 new_data = ReplaceCerts(data.decode())
Tao Bao2ed665a2015-04-01 11:21:55 -0700670 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700671
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700672 # Ask add_img_to_target_files to rebuild the recovery patch if needed.
Tao Bao11f955c2018-06-19 12:19:35 -0700673 elif filename in ("SYSTEM/recovery-from-boot.p",
Robin Leeda427de2020-01-03 19:16:32 +0100674 "VENDOR/recovery-from-boot.p",
675
Tao Bao11f955c2018-06-19 12:19:35 -0700676 "SYSTEM/etc/recovery.img",
Robin Leeda427de2020-01-03 19:16:32 +0100677 "VENDOR/etc/recovery.img",
678
679 "SYSTEM/bin/install-recovery.sh",
680 "VENDOR/bin/install-recovery.sh"):
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700681 OPTIONS.rebuild_recovery = True
Tao Baoa80ed222016-06-16 14:41:24 -0700682
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700683 # Don't copy OTA certs if we're replacing them.
Tianjie Xu2df23d72019-10-15 18:06:25 -0700684 # Replacement of update-payload-key.pub.pem was removed in b/116660991.
Kelvin Zhang9f781ff2021-02-11 19:10:44 -0500685 elif OPTIONS.replace_ota_keys and filename.endswith("/otacerts.zip"):
Doug Zongker412c02f2014-02-13 10:58:24 -0800686 pass
Tao Baoa80ed222016-06-16 14:41:24 -0700687
Tao Bao46a59992017-06-05 11:55:16 -0700688 # Skip META/misc_info.txt since we will write back the new values later.
Tao Bao11f955c2018-06-19 12:19:35 -0700689 elif filename == "META/misc_info.txt":
Geremy Condraf19b3652014-07-29 17:54:54 -0700690 pass
Tao Bao8adcfd12016-06-17 17:01:22 -0700691
692 # Skip verity public key if we will replace it.
Michael Runge947894f2014-10-14 20:58:38 -0700693 elif (OPTIONS.replace_verity_public_key and
Tao Bao11f955c2018-06-19 12:19:35 -0700694 filename in ("BOOT/RAMDISK/verity_key",
695 "ROOT/verity_key")):
Geremy Condraf19b3652014-07-29 17:54:54 -0700696 pass
Bowgo Tsai2fe786a2020-02-21 17:48:18 +0800697 elif (OPTIONS.remove_avb_public_keys and
698 (filename.startswith("BOOT/RAMDISK/avb/") or
699 filename.startswith("BOOT/RAMDISK/first_stage_ramdisk/avb/"))):
Kelvin Zhang0876c412020-06-23 15:06:58 -0400700 matched_removal = False
701 for key_to_remove in OPTIONS.remove_avb_public_keys:
702 if filename.endswith(key_to_remove):
703 matched_removal = True
704 print("Removing AVB public key from ramdisk: %s" % filename)
705 break
706 if not matched_removal:
707 # Copy it verbatim if we don't want to remove it.
708 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoa80ed222016-06-16 14:41:24 -0700709
Tao Bao8adcfd12016-06-17 17:01:22 -0700710 # Skip verity keyid (for system_root_image use) if we will replace it.
Tao Bao11f955c2018-06-19 12:19:35 -0700711 elif OPTIONS.replace_verity_keyid and filename == "BOOT/cmdline":
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700712 pass
713
Tianjiebbde59f2021-05-03 21:18:56 -0700714 # Skip the vbmeta digest as we will recalculate it.
715 elif filename == "META/vbmeta_digest.txt":
716 pass
717
Tianjie Xu4f099002016-08-11 18:04:27 -0700718 # Skip the care_map as we will regenerate the system/vendor images.
Kelvin Zhang0876c412020-06-23 15:06:58 -0400719 elif filename in ["META/care_map.pb", "META/care_map.txt"]:
Tianjie Xu4f099002016-08-11 18:04:27 -0700720 pass
721
Kelvin Zhang5f0fcee2021-01-19 15:30:46 -0500722 # Skip apex_info.pb because we sign/modify apexes
723 elif filename == "META/apex_info.pb":
724 pass
725
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800726 # Updates system_other.avbpubkey in /product/etc/.
727 elif filename in (
728 "PRODUCT/etc/security/avb/system_other.avbpubkey",
Bowgo Tsai2a781692021-10-13 17:39:33 +0800729 "SYSTEM/product/etc/security/avb/system_other.avbpubkey"):
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800730 # Only update system_other's public key, if the corresponding signing
731 # key is specified via --avb_system_other_key.
732 signing_key = OPTIONS.avb_keys.get("system_other")
733 if signing_key:
Tao Bao1ac886e2019-06-26 11:58:22 -0700734 public_key = common.ExtractAvbPublicKey(
735 misc_info['avb_avbtool'], signing_key)
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800736 print(" Rewriting AVB public key of system_other in /product")
737 common.ZipWrite(output_tf_zip, public_key, filename)
738
Andrew Scullbbc930b2022-02-17 22:34:27 +0000739 # Updates pvmfw embedded public key with the virt APEX payload key.
740 elif filename == "PREBUILT_IMAGES/pvmfw.img":
741 # Find the name of the virt APEX in the target files.
742 namelist = input_tf_zip.namelist()
743 apex_gen = (GetApexFilename(f) for f in namelist if IsApexFile(f))
744 virt_apex_re = re.compile("^com\.([^\.]+\.)?android\.virt\.apex$")
745 virt_apex = next((a for a in apex_gen if virt_apex_re.match(a)), None)
746 if not virt_apex:
747 print("Removing %s from ramdisk: virt APEX not found" % filename)
748 else:
749 print("Replacing %s embedded key with %s key" % (filename, virt_apex))
750 # Get the current and new embedded keys.
751 payload_key, container_key, sign_tool = apex_keys[virt_apex]
752 new_pubkey_path = common.ExtractAvbPublicKey(
753 misc_info['avb_avbtool'], payload_key)
754 with open(new_pubkey_path, 'rb') as f:
755 new_pubkey = f.read()
756 pubkey_info = copy.copy(
757 input_tf_zip.getinfo("PREBUILT_IMAGES/pvmfw_embedded.avbpubkey"))
758 old_pubkey = input_tf_zip.read(pubkey_info.filename)
759 # Validate the keys and image.
760 if len(old_pubkey) != len(new_pubkey):
761 raise common.ExternalError("pvmfw embedded public key size mismatch")
762 pos = data.find(old_pubkey)
763 if pos == -1:
764 raise common.ExternalError("pvmfw embedded public key not found")
765 # Replace the key and copy new files.
766 new_data = data[:pos] + new_pubkey + data[pos+len(old_pubkey):]
767 common.ZipWriteStr(output_tf_zip, out_info, new_data)
768 common.ZipWriteStr(output_tf_zip, pubkey_info, new_pubkey)
769 elif filename == "PREBUILT_IMAGES/pvmfw_embedded.avbpubkey":
770 pass
771
Bowgo Tsai78369eb2019-04-23 12:28:44 +0800772 # Should NOT sign boot-debug.img.
773 elif filename in (
774 "BOOT/RAMDISK/force_debuggable",
Bowgo Tsai2a781692021-10-13 17:39:33 +0800775 "BOOT/RAMDISK/first_stage_ramdisk/force_debuggable"):
Bowgo Tsai78369eb2019-04-23 12:28:44 +0800776 raise common.ExternalError("debuggable boot.img cannot be signed")
777
Bowgo Tsai2a781692021-10-13 17:39:33 +0800778 # Should NOT sign userdebug sepolicy file.
779 elif filename in (
780 "SYSTEM_EXT/etc/selinux/userdebug_plat_sepolicy.cil",
781 "SYSTEM/system_ext/etc/selinux/userdebug_plat_sepolicy.cil"):
782 if not OPTIONS.allow_gsi_debug_sepolicy:
783 raise common.ExternalError("debug sepolicy shouldn't be included")
784 else:
785 # Copy it verbatim if we allow the file to exist.
786 common.ZipWriteStr(output_tf_zip, out_info, data)
787
Tao Baoa80ed222016-06-16 14:41:24 -0700788 # A non-APK file; copy it verbatim.
Doug Zongkereef39442009-04-02 12:14:19 -0700789 else:
Tao Bao2ed665a2015-04-01 11:21:55 -0700790 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700791
Doug Zongker412c02f2014-02-13 10:58:24 -0800792 if OPTIONS.replace_ota_keys:
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700793 ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info)
Doug Zongker412c02f2014-02-13 10:58:24 -0800794
Tao Bao46a59992017-06-05 11:55:16 -0700795 # Replace the keyid string in misc_info dict.
Tao Bao8adcfd12016-06-17 17:01:22 -0700796 if OPTIONS.replace_verity_private_key:
Tao Bao46a59992017-06-05 11:55:16 -0700797 ReplaceVerityPrivateKey(misc_info, OPTIONS.replace_verity_private_key[1])
Tao Bao8adcfd12016-06-17 17:01:22 -0700798
799 if OPTIONS.replace_verity_public_key:
Tao Baoc9981932019-09-16 12:10:43 -0700800 # Replace the one in root dir in system.img.
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700801 ReplaceVerityPublicKey(
Tao Baoc9981932019-09-16 12:10:43 -0700802 output_tf_zip, 'ROOT/verity_key', OPTIONS.replace_verity_public_key[1])
803
804 if not system_root_image:
805 # Additionally replace the copy in ramdisk if not using system-as-root.
806 ReplaceVerityPublicKey(
807 output_tf_zip,
808 'BOOT/RAMDISK/verity_key',
809 OPTIONS.replace_verity_public_key[1])
Tao Bao8adcfd12016-06-17 17:01:22 -0700810
811 # Replace the keyid string in BOOT/cmdline.
812 if OPTIONS.replace_verity_keyid:
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700813 ReplaceVerityKeyId(input_tf_zip, output_tf_zip,
814 OPTIONS.replace_verity_keyid[1])
Doug Zongker412c02f2014-02-13 10:58:24 -0800815
Tao Bao639118f2017-06-19 15:48:02 -0700816 # Replace the AVB signing keys, if any.
817 ReplaceAvbSigningKeys(misc_info)
818
Tao Bao19b02fe2019-10-09 00:04:28 -0700819 # Rewrite the props in AVB signing args.
820 if misc_info.get('avb_enable') == 'true':
821 RewriteAvbProps(misc_info)
822
Bowgo Tsai27c39b02021-03-12 21:40:32 +0800823 # Replace the GKI signing key for boot.img, if any.
824 ReplaceGkiSigningKey(misc_info)
825
Tao Bao46a59992017-06-05 11:55:16 -0700826 # Write back misc_info with the latest values.
827 ReplaceMiscInfoTxt(input_tf_zip, output_tf_zip, misc_info)
828
Doug Zongker8e931bf2009-04-06 15:21:45 -0700829
Robert Craig817c5742013-04-19 10:59:22 -0400830def ReplaceCerts(data):
Tao Bao66472632017-12-04 17:16:36 -0800831 """Replaces all the occurences of X.509 certs with the new ones.
Robert Craig817c5742013-04-19 10:59:22 -0400832
Tao Bao66472632017-12-04 17:16:36 -0800833 The mapping info is read from OPTIONS.key_map. Non-existent certificate will
834 be skipped. After the replacement, it additionally checks for duplicate
835 entries, which would otherwise fail the policy loading code in
836 frameworks/base/services/core/java/com/android/server/pm/SELinuxMMAC.java.
837
838 Args:
839 data: Input string that contains a set of X.509 certs.
840
841 Returns:
842 A string after the replacement.
843
844 Raises:
845 AssertionError: On finding duplicate entries.
846 """
Tao Baoa3705452019-06-24 15:33:41 -0700847 for old, new in OPTIONS.key_map.items():
Tao Bao66472632017-12-04 17:16:36 -0800848 if OPTIONS.verbose:
849 print(" Replacing %s.x509.pem with %s.x509.pem" % (old, new))
850
851 try:
852 with open(old + ".x509.pem") as old_fp:
853 old_cert16 = base64.b16encode(
Tao Baoa3705452019-06-24 15:33:41 -0700854 common.ParseCertificate(old_fp.read())).decode().lower()
Tao Bao66472632017-12-04 17:16:36 -0800855 with open(new + ".x509.pem") as new_fp:
856 new_cert16 = base64.b16encode(
Tao Baoa3705452019-06-24 15:33:41 -0700857 common.ParseCertificate(new_fp.read())).decode().lower()
Tao Bao66472632017-12-04 17:16:36 -0800858 except IOError as e:
859 if OPTIONS.verbose or e.errno != errno.ENOENT:
860 print(" Error accessing %s: %s.\nSkip replacing %s.x509.pem with "
861 "%s.x509.pem." % (e.filename, e.strerror, old, new))
862 continue
863
864 # Only match entire certs.
865 pattern = "\\b" + old_cert16 + "\\b"
866 (data, num) = re.subn(pattern, new_cert16, data, flags=re.IGNORECASE)
867
868 if OPTIONS.verbose:
869 print(" Replaced %d occurence(s) of %s.x509.pem with %s.x509.pem" % (
870 num, old, new))
871
872 # Verify that there're no duplicate entries after the replacement. Note that
873 # it's only checking entries with global seinfo at the moment (i.e. ignoring
874 # the ones with inner packages). (Bug: 69479366)
875 root = ElementTree.fromstring(data)
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400876 signatures = [signer.attrib['signature']
877 for signer in root.findall('signer')]
Tao Bao66472632017-12-04 17:16:36 -0800878 assert len(signatures) == len(set(signatures)), \
879 "Found duplicate entries after cert replacement: {}".format(data)
Robert Craig817c5742013-04-19 10:59:22 -0400880
881 return data
882
883
Doug Zongkerc09abc82010-01-11 13:09:15 -0800884def EditTags(tags):
Tao Baoa7054ee2017-12-08 14:42:16 -0800885 """Applies the edits to the tag string as specified in OPTIONS.tag_changes.
886
887 Args:
888 tags: The input string that contains comma-separated tags.
889
890 Returns:
891 The updated tags (comma-separated and sorted).
892 """
Doug Zongkerc09abc82010-01-11 13:09:15 -0800893 tags = set(tags.split(","))
894 for ch in OPTIONS.tag_changes:
895 if ch[0] == "-":
896 tags.discard(ch[1:])
897 elif ch[0] == "+":
898 tags.add(ch[1:])
899 return ",".join(sorted(tags))
900
901
Tao Baoa7054ee2017-12-08 14:42:16 -0800902def RewriteProps(data):
903 """Rewrites the system properties in the given string.
904
905 Each property is expected in 'key=value' format. The properties that contain
906 build tags (i.e. test-keys, dev-keys) will be updated accordingly by calling
907 EditTags().
908
909 Args:
910 data: Input string, separated by newlines.
911
912 Returns:
913 The string with modified properties.
914 """
Doug Zongker17aa9442009-04-17 10:15:58 -0700915 output = []
916 for line in data.split("\n"):
917 line = line.strip()
918 original_line = line
Michael Rungedc2661a2014-06-03 14:43:11 -0700919 if line and line[0] != '#' and "=" in line:
Doug Zongker17aa9442009-04-17 10:15:58 -0700920 key, value = line.split("=", 1)
Magnus Strandh234f4b42019-05-01 23:09:30 +0200921 if (key.startswith("ro.") and
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400922 key.endswith((".build.fingerprint", ".build.thumbprint"))):
Doug Zongkerc09abc82010-01-11 13:09:15 -0800923 pieces = value.split("/")
924 pieces[-1] = EditTags(pieces[-1])
925 value = "/".join(pieces)
Tao Baocb7ff772015-09-11 15:27:56 -0700926 elif key == "ro.bootimage.build.fingerprint":
927 pieces = value.split("/")
928 pieces[-1] = EditTags(pieces[-1])
929 value = "/".join(pieces)
Doug Zongker17aa9442009-04-17 10:15:58 -0700930 elif key == "ro.build.description":
Doug Zongkerc09abc82010-01-11 13:09:15 -0800931 pieces = value.split(" ")
Stefen Wakefield4260fc12021-03-23 04:58:22 -0500932 assert pieces[-1].endswith("-keys")
Doug Zongkerc09abc82010-01-11 13:09:15 -0800933 pieces[-1] = EditTags(pieces[-1])
934 value = " ".join(pieces)
Magnus Strandh234f4b42019-05-01 23:09:30 +0200935 elif key.startswith("ro.") and key.endswith(".build.tags"):
Doug Zongkerc09abc82010-01-11 13:09:15 -0800936 value = EditTags(value)
Doug Zongkera8608a72013-07-23 11:51:04 -0700937 elif key == "ro.build.display.id":
938 # change, eg, "JWR66N dev-keys" to "JWR66N"
939 value = value.split()
Michael Rungedc2661a2014-06-03 14:43:11 -0700940 if len(value) > 1 and value[-1].endswith("-keys"):
Andrew Boie73d5abb2013-12-11 12:42:03 -0800941 value.pop()
942 value = " ".join(value)
Doug Zongkerc09abc82010-01-11 13:09:15 -0800943 line = key + "=" + value
Doug Zongker17aa9442009-04-17 10:15:58 -0700944 if line != original_line:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800945 print(" replace: ", original_line)
946 print(" with: ", line)
Doug Zongker17aa9442009-04-17 10:15:58 -0700947 output.append(line)
948 return "\n".join(output) + "\n"
949
950
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700951def WriteOtacerts(output_zip, filename, keys):
952 """Constructs a zipfile from given keys; and writes it to output_zip.
953
954 Args:
955 output_zip: The output target_files zip.
956 filename: The archive name in the output zip.
957 keys: A list of public keys to use during OTA package verification.
958 """
Tao Baobb733882019-07-24 23:31:19 -0700959 temp_file = io.BytesIO()
Kelvin Zhang928c2342020-09-22 16:15:57 -0400960 certs_zip = zipfile.ZipFile(temp_file, "w", allowZip64=True)
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700961 for k in keys:
962 common.ZipWrite(certs_zip, k)
963 common.ZipClose(certs_zip)
964 common.ZipWriteStr(output_zip, filename, temp_file.getvalue())
965
966
Doug Zongker831840e2011-09-22 10:28:04 -0700967def ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info):
Doug Zongker8e931bf2009-04-06 15:21:45 -0700968 try:
969 keylist = input_tf_zip.read("META/otakeys.txt").split()
970 except KeyError:
T.R. Fullharta28acc62013-03-18 10:31:26 -0700971 raise common.ExternalError("can't read META/otakeys.txt from input")
Doug Zongker8e931bf2009-04-06 15:21:45 -0700972
Jacky Liubeb0b692021-12-29 16:29:05 +0800973 extra_ota_keys_info = misc_info.get("extra_ota_keys")
974 if extra_ota_keys_info:
975 extra_ota_keys = [OPTIONS.key_map.get(k, k) + ".x509.pem"
976 for k in extra_ota_keys_info.split()]
977 print("extra ota key(s): " + ", ".join(extra_ota_keys))
978 else:
979 extra_ota_keys = []
980 for k in extra_ota_keys:
981 if not os.path.isfile(k):
982 raise common.ExternalError(k + " does not exist or is not a file")
983
984 extra_recovery_keys_info = misc_info.get("extra_recovery_keys")
985 if extra_recovery_keys_info:
Doug Zongkere121d6a2011-02-01 14:13:52 -0800986 extra_recovery_keys = [OPTIONS.key_map.get(k, k) + ".x509.pem"
Jacky Liubeb0b692021-12-29 16:29:05 +0800987 for k in extra_recovery_keys_info.split()]
988 print("extra recovery-only key(s): " + ", ".join(extra_recovery_keys))
Doug Zongkere121d6a2011-02-01 14:13:52 -0800989 else:
990 extra_recovery_keys = []
Jacky Liubeb0b692021-12-29 16:29:05 +0800991 for k in extra_recovery_keys:
992 if not os.path.isfile(k):
993 raise common.ExternalError(k + " does not exist or is not a file")
Doug Zongkere121d6a2011-02-01 14:13:52 -0800994
Doug Zongker8e931bf2009-04-06 15:21:45 -0700995 mapped_keys = []
996 for k in keylist:
997 m = re.match(r"^(.*)\.x509\.pem$", k)
998 if not m:
Doug Zongker412c02f2014-02-13 10:58:24 -0800999 raise common.ExternalError(
1000 "can't parse \"%s\" from META/otakeys.txt" % (k,))
Doug Zongker8e931bf2009-04-06 15:21:45 -07001001 k = m.group(1)
1002 mapped_keys.append(OPTIONS.key_map.get(k, k) + ".x509.pem")
1003
Doug Zongkere05628c2009-08-20 17:38:42 -07001004 if mapped_keys:
Tao Bao0c28d2d2017-12-24 10:37:38 -08001005 print("using:\n ", "\n ".join(mapped_keys))
1006 print("for OTA package verification")
Doug Zongkere05628c2009-08-20 17:38:42 -07001007 else:
Doug Zongker831840e2011-09-22 10:28:04 -07001008 devkey = misc_info.get("default_system_dev_certificate",
Dan Willemsen0ab1be62019-04-09 21:35:37 -07001009 "build/make/target/product/security/testkey")
Tao Baof718f902017-11-09 10:10:10 -08001010 mapped_devkey = OPTIONS.key_map.get(devkey, devkey)
1011 if mapped_devkey != devkey:
1012 misc_info["default_system_dev_certificate"] = mapped_devkey
1013 mapped_keys.append(mapped_devkey + ".x509.pem")
Tao Baoa80ed222016-06-16 14:41:24 -07001014 print("META/otakeys.txt has no keys; using %s for OTA package"
1015 " verification." % (mapped_keys[0],))
Jacky Liubeb0b692021-12-29 16:29:05 +08001016 for k in mapped_keys:
1017 if not os.path.isfile(k):
1018 raise common.ExternalError(k + " does not exist or is not a file")
Doug Zongker8e931bf2009-04-06 15:21:45 -07001019
Kelvin Zhang9f781ff2021-02-11 19:10:44 -05001020 otacerts = [info
1021 for info in input_tf_zip.infolist()
1022 if info.filename.endswith("/otacerts.zip")]
1023 for info in otacerts:
Jacky Liubeb0b692021-12-29 16:29:05 +08001024 if info.filename.startswith(("BOOT/", "RECOVERY/", "VENDOR_BOOT/")):
1025 extra_keys = extra_recovery_keys
1026 else:
1027 extra_keys = extra_ota_keys
1028 print("Rewriting OTA key:", info.filename, mapped_keys + extra_keys)
1029 WriteOtacerts(output_tf_zip, info.filename, mapped_keys + extra_keys)
Doug Zongkereef39442009-04-02 12:14:19 -07001030
Tao Baoa80ed222016-06-16 14:41:24 -07001031
Tao Bao0c28d2d2017-12-24 10:37:38 -08001032def ReplaceVerityPublicKey(output_zip, filename, key_path):
1033 """Replaces the verity public key at the given path in the given zip.
1034
1035 Args:
1036 output_zip: The output target_files zip.
1037 filename: The archive name in the output zip.
1038 key_path: The path to the public key.
1039 """
1040 print("Replacing verity public key with %s" % (key_path,))
1041 common.ZipWrite(output_zip, key_path, arcname=filename)
Geremy Condraf19b3652014-07-29 17:54:54 -07001042
Tao Bao8adcfd12016-06-17 17:01:22 -07001043
Tao Bao46a59992017-06-05 11:55:16 -07001044def ReplaceVerityPrivateKey(misc_info, key_path):
Tao Bao0c28d2d2017-12-24 10:37:38 -08001045 """Replaces the verity private key in misc_info dict.
1046
1047 Args:
1048 misc_info: The info dict.
1049 key_path: The path to the private key in PKCS#8 format.
1050 """
1051 print("Replacing verity private key with %s" % (key_path,))
Andrew Boied083f0b2014-09-15 16:01:07 -07001052 misc_info["verity_key"] = key_path
Doug Zongkereef39442009-04-02 12:14:19 -07001053
Tao Bao8adcfd12016-06-17 17:01:22 -07001054
Tao Baoe838d142017-12-23 23:44:48 -08001055def ReplaceVerityKeyId(input_zip, output_zip, key_path):
1056 """Replaces the veritykeyid parameter in BOOT/cmdline.
1057
1058 Args:
1059 input_zip: The input target_files zip, which should be already open.
1060 output_zip: The output target_files zip, which should be already open and
1061 writable.
1062 key_path: The path to the PEM encoded X.509 certificate.
1063 """
Tao Baoa3705452019-06-24 15:33:41 -07001064 in_cmdline = input_zip.read("BOOT/cmdline").decode()
Tao Baoe838d142017-12-23 23:44:48 -08001065 # Copy in_cmdline to output_zip if veritykeyid is not present.
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001066 if "veritykeyid" not in in_cmdline:
Tao Baoe838d142017-12-23 23:44:48 -08001067 common.ZipWriteStr(output_zip, "BOOT/cmdline", in_cmdline)
1068 return
1069
Tao Bao0c28d2d2017-12-24 10:37:38 -08001070 out_buffer = []
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001071 for param in in_cmdline.split():
Tao Baoe838d142017-12-23 23:44:48 -08001072 if "veritykeyid" not in param:
Tao Bao0c28d2d2017-12-24 10:37:38 -08001073 out_buffer.append(param)
Tao Baoe838d142017-12-23 23:44:48 -08001074 continue
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001075
Tao Baoe838d142017-12-23 23:44:48 -08001076 # Extract keyid using openssl command.
1077 p = common.Run(["openssl", "x509", "-in", key_path, "-text"],
Tao Baode1d4792018-02-20 10:05:46 -08001078 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
Tao Baoe838d142017-12-23 23:44:48 -08001079 keyid, stderr = p.communicate()
1080 assert p.returncode == 0, "Failed to dump certificate: {}".format(stderr)
1081 keyid = re.search(
1082 r'keyid:([0-9a-fA-F:]*)', keyid).group(1).replace(':', '').lower()
1083 print("Replacing verity keyid with {}".format(keyid))
1084 out_buffer.append("veritykeyid=id:%s" % (keyid,))
1085
1086 out_cmdline = ' '.join(out_buffer).strip() + '\n'
1087 common.ZipWriteStr(output_zip, "BOOT/cmdline", out_cmdline)
Tao Bao46a59992017-06-05 11:55:16 -07001088
1089
1090def ReplaceMiscInfoTxt(input_zip, output_zip, misc_info):
1091 """Replaces META/misc_info.txt.
1092
1093 Only writes back the ones in the original META/misc_info.txt. Because the
1094 current in-memory dict contains additional items computed at runtime.
1095 """
1096 misc_info_old = common.LoadDictionaryFromLines(
Tao Baoa3705452019-06-24 15:33:41 -07001097 input_zip.read('META/misc_info.txt').decode().split('\n'))
Tao Bao46a59992017-06-05 11:55:16 -07001098 items = []
1099 for key in sorted(misc_info):
1100 if key in misc_info_old:
1101 items.append('%s=%s' % (key, misc_info[key]))
1102 common.ZipWriteStr(output_zip, "META/misc_info.txt", '\n'.join(items))
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001103
Tao Bao8adcfd12016-06-17 17:01:22 -07001104
Tao Bao639118f2017-06-19 15:48:02 -07001105def ReplaceAvbSigningKeys(misc_info):
1106 """Replaces the AVB signing keys."""
1107
Tao Bao639118f2017-06-19 15:48:02 -07001108 def ReplaceAvbPartitionSigningKey(partition):
1109 key = OPTIONS.avb_keys.get(partition)
1110 if not key:
1111 return
1112
1113 algorithm = OPTIONS.avb_algorithms.get(partition)
1114 assert algorithm, 'Missing AVB signing algorithm for %s' % (partition,)
1115
Tao Bao0c28d2d2017-12-24 10:37:38 -08001116 print('Replacing AVB signing key for %s with "%s" (%s)' % (
1117 partition, key, algorithm))
Tao Bao639118f2017-06-19 15:48:02 -07001118 misc_info['avb_' + partition + '_algorithm'] = algorithm
1119 misc_info['avb_' + partition + '_key_path'] = key
1120
1121 extra_args = OPTIONS.avb_extra_args.get(partition)
1122 if extra_args:
Tao Bao0c28d2d2017-12-24 10:37:38 -08001123 print('Setting extra AVB signing args for %s to "%s"' % (
1124 partition, extra_args))
Kelvin Zhang0876c412020-06-23 15:06:58 -04001125 args_key = AVB_FOOTER_ARGS_BY_PARTITION.get(
1126 partition,
1127 # custom partition
1128 "avb_{}_add_hashtree_footer_args".format(partition))
Tao Bao639118f2017-06-19 15:48:02 -07001129 misc_info[args_key] = (misc_info.get(args_key, '') + ' ' + extra_args)
1130
1131 for partition in AVB_FOOTER_ARGS_BY_PARTITION:
1132 ReplaceAvbPartitionSigningKey(partition)
1133
Hongguang Chenf23364d2020-04-27 18:36:36 -07001134 for custom_partition in misc_info.get(
Kelvin Zhang7cab7502021-08-02 19:58:14 -04001135 "avb_custom_images_partition_list", "").strip().split():
Hongguang Chenf23364d2020-04-27 18:36:36 -07001136 ReplaceAvbPartitionSigningKey(custom_partition)
1137
Tao Bao639118f2017-06-19 15:48:02 -07001138
Tao Bao19b02fe2019-10-09 00:04:28 -07001139def RewriteAvbProps(misc_info):
1140 """Rewrites the props in AVB signing args."""
1141 for partition, args_key in AVB_FOOTER_ARGS_BY_PARTITION.items():
1142 args = misc_info.get(args_key)
1143 if not args:
1144 continue
1145
1146 tokens = []
1147 changed = False
1148 for token in args.split(' '):
1149 fingerprint_key = 'com.android.build.{}.fingerprint'.format(partition)
1150 if not token.startswith(fingerprint_key):
1151 tokens.append(token)
1152 continue
1153 prefix, tag = token.rsplit('/', 1)
1154 tokens.append('{}/{}'.format(prefix, EditTags(tag)))
1155 changed = True
1156
1157 if changed:
1158 result = ' '.join(tokens)
1159 print('Rewriting AVB prop for {}:\n'.format(partition))
1160 print(' replace: {}'.format(args))
1161 print(' with: {}'.format(result))
1162 misc_info[args_key] = result
1163
1164
Bowgo Tsai27c39b02021-03-12 21:40:32 +08001165def ReplaceGkiSigningKey(misc_info):
1166 """Replaces the GKI signing key."""
1167
1168 key = OPTIONS.gki_signing_key
1169 if not key:
1170 return
1171
1172 algorithm = OPTIONS.gki_signing_algorithm
1173 if not algorithm:
1174 raise ValueError("Missing --gki_signing_algorithm")
1175
1176 print('Replacing GKI signing key with "%s" (%s)' % (key, algorithm))
1177 misc_info["gki_signing_algorithm"] = algorithm
1178 misc_info["gki_signing_key_path"] = key
1179
1180 extra_args = OPTIONS.gki_signing_extra_args
1181 if extra_args:
Bowgo Tsaibcae74d2021-05-10 17:35:37 +08001182 print('Setting GKI signing args: "%s"' % (extra_args))
1183 misc_info["gki_signing_signature_args"] = extra_args
Bowgo Tsai27c39b02021-03-12 21:40:32 +08001184
1185
Doug Zongker831840e2011-09-22 10:28:04 -07001186def BuildKeyMap(misc_info, key_mapping_options):
1187 for s, d in key_mapping_options:
1188 if s is None: # -d option
1189 devkey = misc_info.get("default_system_dev_certificate",
Dan Willemsen0ab1be62019-04-09 21:35:37 -07001190 "build/make/target/product/security/testkey")
Doug Zongker831840e2011-09-22 10:28:04 -07001191 devkeydir = os.path.dirname(devkey)
1192
1193 OPTIONS.key_map.update({
1194 devkeydir + "/testkey": d + "/releasekey",
1195 devkeydir + "/devkey": d + "/releasekey",
1196 devkeydir + "/media": d + "/media",
1197 devkeydir + "/shared": d + "/shared",
1198 devkeydir + "/platform": d + "/platform",
Oleh Cherpak982e6082019-12-10 12:58:54 +02001199 devkeydir + "/networkstack": d + "/networkstack",
Kelvin Zhang7cab7502021-08-02 19:58:14 -04001200 })
Doug Zongker831840e2011-09-22 10:28:04 -07001201 else:
1202 OPTIONS.key_map[s] = d
1203
1204
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001205def GetApiLevelAndCodename(input_tf_zip):
Tao Baoa3705452019-06-24 15:33:41 -07001206 data = input_tf_zip.read("SYSTEM/build.prop").decode()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001207 api_level = None
1208 codename = None
1209 for line in data.split("\n"):
1210 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001211 if line and line[0] != '#' and "=" in line:
1212 key, value = line.split("=", 1)
1213 key = key.strip()
1214 if key == "ro.build.version.sdk":
1215 api_level = int(value.strip())
1216 elif key == "ro.build.version.codename":
1217 codename = value.strip()
1218
1219 if api_level is None:
1220 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
1221 if codename is None:
1222 raise ValueError("No ro.build.version.codename in SYSTEM/build.prop")
1223
1224 return (api_level, codename)
1225
1226
1227def GetCodenameToApiLevelMap(input_tf_zip):
Tao Baoa3705452019-06-24 15:33:41 -07001228 data = input_tf_zip.read("SYSTEM/build.prop").decode()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001229 api_level = None
1230 codenames = None
1231 for line in data.split("\n"):
1232 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001233 if line and line[0] != '#' and "=" in line:
1234 key, value = line.split("=", 1)
1235 key = key.strip()
1236 if key == "ro.build.version.sdk":
1237 api_level = int(value.strip())
1238 elif key == "ro.build.version.all_codenames":
1239 codenames = value.strip().split(",")
1240
1241 if api_level is None:
1242 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
1243 if codenames is None:
1244 raise ValueError("No ro.build.version.all_codenames in SYSTEM/build.prop")
1245
Tao Baoa3705452019-06-24 15:33:41 -07001246 result = {}
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001247 for codename in codenames:
1248 codename = codename.strip()
Tao Baobadceb22019-03-15 09:33:43 -07001249 if codename:
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001250 result[codename] = api_level
1251 return result
1252
1253
Tao Baoaa7e9932019-03-15 09:37:01 -07001254def ReadApexKeysInfo(tf_zip):
1255 """Parses the APEX keys info from a given target-files zip.
1256
Melisa Carranza Zunigae6d4fb52022-03-07 14:56:26 +01001257 Given a target-files ZipFile, parses the META/apexkeys.txt entry and returns
1258 two dicts, the first one contains the mapping from APEX names
1259 (e.g. com.android.tzdata) to a tuple of (payload_key, container_key,
1260 sign_tool). The second one maps the sepolicy APEX name to a tuple containing
1261 (sepolicy_key, sepolicy_cert, fsverity_tool).
Tao Baoaa7e9932019-03-15 09:37:01 -07001262
1263 Args:
1264 tf_zip: The input target_files ZipFile (already open).
1265
1266 Returns:
Melisa Carranza Zunigae6d4fb52022-03-07 14:56:26 +01001267 name : (payload_key, container_key, sign_tool)
Jooyung Han8caba5e2021-10-27 03:58:09 +09001268 - payload_key contains the path to the payload signing key
1269 - container_key contains the path to the container signing key
1270 - sign_tool is an apex-specific signing tool for its payload contents
Melisa Carranza Zunigae6d4fb52022-03-07 14:56:26 +01001271 name : (sepolicy_key, sepolicy_cert, fsverity_tool)
Tao Baoaa7e9932019-03-15 09:37:01 -07001272 """
1273 keys = {}
Melisa Carranza Zunigae6d4fb52022-03-07 14:56:26 +01001274 sepolicy_keys = {}
Tao Baoa3705452019-06-24 15:33:41 -07001275 for line in tf_zip.read('META/apexkeys.txt').decode().split('\n'):
Tao Baoaa7e9932019-03-15 09:37:01 -07001276 line = line.strip()
1277 if not line:
1278 continue
1279 matches = re.match(
1280 r'^name="(?P<NAME>.*)"\s+'
1281 r'public_key="(?P<PAYLOAD_PUBLIC_KEY>.*)"\s+'
1282 r'private_key="(?P<PAYLOAD_PRIVATE_KEY>.*)"\s+'
1283 r'container_certificate="(?P<CONTAINER_CERT>.*)"\s+'
Bill Peckham5c7b0342020-04-03 15:36:23 -07001284 r'container_private_key="(?P<CONTAINER_PRIVATE_KEY>.*?)"'
Melisa Carranza Zunigae6d4fb52022-03-07 14:56:26 +01001285 r'(\s+sepolicy_key="(?P<SEPOLICY_KEY>.*?)")?'
1286 r'(\s+sepolicy_certificate="(?P<SEPOLICY_CERT>.*?)")?'
1287 r'(\s+fsverity_tool="(?P<FSVERITY_TOOL>.*?)")?'
Jooyung Han8caba5e2021-10-27 03:58:09 +09001288 r'(\s+partition="(?P<PARTITION>.*?)")?'
1289 r'(\s+sign_tool="(?P<SIGN_TOOL>.*?)")?$',
Tao Baoaa7e9932019-03-15 09:37:01 -07001290 line)
1291 if not matches:
1292 continue
1293
1294 name = matches.group('NAME')
Tao Baoaa7e9932019-03-15 09:37:01 -07001295 payload_private_key = matches.group("PAYLOAD_PRIVATE_KEY")
1296
1297 def CompareKeys(pubkey, pubkey_suffix, privkey, privkey_suffix):
1298 pubkey_suffix_len = len(pubkey_suffix)
1299 privkey_suffix_len = len(privkey_suffix)
1300 return (pubkey.endswith(pubkey_suffix) and
1301 privkey.endswith(privkey_suffix) and
1302 pubkey[:-pubkey_suffix_len] == privkey[:-privkey_suffix_len])
1303
Ivan Lozanob021b2a2020-07-28 09:31:06 -04001304 # Check the container key names, as we'll carry them without the
Tao Bao6d9e3da2019-03-26 12:59:25 -07001305 # extensions. This doesn't apply to payload keys though, which we will use
1306 # full names only.
Tao Baoaa7e9932019-03-15 09:37:01 -07001307 container_cert = matches.group("CONTAINER_CERT")
1308 container_private_key = matches.group("CONTAINER_PRIVATE_KEY")
Tao Baof454c3a2019-04-24 23:53:42 -07001309 if container_cert == 'PRESIGNED' and container_private_key == 'PRESIGNED':
1310 container_key = 'PRESIGNED'
1311 elif CompareKeys(
Kelvin Zhang7cab7502021-08-02 19:58:14 -04001312 container_cert, OPTIONS.public_key_suffix,
1313 container_private_key, OPTIONS.private_key_suffix):
Tao Baof454c3a2019-04-24 23:53:42 -07001314 container_key = container_cert[:-len(OPTIONS.public_key_suffix)]
1315 else:
Melisa Carranza Zunigae6d4fb52022-03-07 14:56:26 +01001316 raise ValueError("Failed to parse container keys: \n{} **** {}".format(container_cert, container_private_key))
Tao Baoaa7e9932019-03-15 09:37:01 -07001317
Jooyung Han8caba5e2021-10-27 03:58:09 +09001318 sign_tool = matches.group("SIGN_TOOL")
1319 keys[name] = (payload_private_key, container_key, sign_tool)
Tao Baoaa7e9932019-03-15 09:37:01 -07001320
Melisa Carranza Zunigae6d4fb52022-03-07 14:56:26 +01001321 if IsSepolicyApex(name):
1322 sepolicy_key = matches.group('SEPOLICY_KEY')
1323 sepolicy_cert = matches.group('SEPOLICY_CERT')
1324 fsverity_tool = matches.group('FSVERITY_TOOL')
1325 sepolicy_keys[name] = (sepolicy_key, sepolicy_cert, fsverity_tool)
1326
1327 return keys, sepolicy_keys
Tao Baoaa7e9932019-03-15 09:37:01 -07001328
1329
Daniel Norman78554ea2021-09-14 10:29:38 -07001330def BuildVendorPartitions(output_zip_path):
1331 """Builds OPTIONS.vendor_partitions using OPTIONS.vendor_otatools."""
1332 if OPTIONS.vendor_partitions.difference(ALLOWED_VENDOR_PARTITIONS):
1333 logger.warning("Allowed --vendor_partitions: %s",
1334 ",".join(ALLOWED_VENDOR_PARTITIONS))
1335 OPTIONS.vendor_partitions = ALLOWED_VENDOR_PARTITIONS.intersection(
1336 OPTIONS.vendor_partitions)
1337
1338 logger.info("Building vendor partitions using vendor otatools.")
1339 vendor_tempdir = common.UnzipTemp(output_zip_path, [
1340 "META/*",
Po Hu0663ae42021-09-27 12:59:06 +08001341 "SYSTEM/build.prop",
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001342 "RECOVERY/*",
1343 "BOOT/*",
1344 "OTA/",
Daniel Norman78554ea2021-09-14 10:29:38 -07001345 ] + ["{}/*".format(p.upper()) for p in OPTIONS.vendor_partitions])
1346
1347 # Disable various partitions that build based on misc_info fields.
1348 # Only partitions in ALLOWED_VENDOR_PARTITIONS can be rebuilt using
1349 # vendor otatools. These other partitions will be rebuilt using the main
1350 # otatools if necessary.
1351 vendor_misc_info_path = os.path.join(vendor_tempdir, "META/misc_info.txt")
1352 vendor_misc_info = common.LoadDictionaryFromFile(vendor_misc_info_path)
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001353 # Ignore if not rebuilding recovery
1354 if not OPTIONS.rebuild_recovery:
1355 vendor_misc_info["no_boot"] = "true" # boot
1356 vendor_misc_info["vendor_boot"] = "false" # vendor_boot
1357 vendor_misc_info["no_recovery"] = "true" # recovery
Iavor-Valentin Iftime40adb172022-04-19 18:17:56 +00001358 vendor_misc_info["avb_enable"] = "false" # vbmeta
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001359
Daniel Norman78554ea2021-09-14 10:29:38 -07001360 vendor_misc_info["board_bpt_enable"] = "false" # partition-table
1361 vendor_misc_info["has_dtbo"] = "false" # dtbo
1362 vendor_misc_info["has_pvmfw"] = "false" # pvmfw
1363 vendor_misc_info["avb_custom_images_partition_list"] = "" # custom images
Iavor-Valentin Iftime40adb172022-04-19 18:17:56 +00001364 vendor_misc_info["avb_building_vbmeta_image"] = "false" # skip building vbmeta
Daniel Norman78554ea2021-09-14 10:29:38 -07001365 vendor_misc_info["use_dynamic_partitions"] = "false" # super_empty
1366 vendor_misc_info["build_super_partition"] = "false" # super split
1367 with open(vendor_misc_info_path, "w") as output:
1368 for key in sorted(vendor_misc_info):
1369 output.write("{}={}\n".format(key, vendor_misc_info[key]))
1370
Po Hu0663ae42021-09-27 12:59:06 +08001371 # Disable system partition by a placeholder of IMAGES/system.img,
1372 # instead of removing SYSTEM folder.
1373 # Because SYSTEM/build.prop is still needed for:
1374 # add_img_to_target_files.CreateImage ->
1375 # common.BuildInfo ->
1376 # common.BuildInfo.CalculateFingerprint
1377 vendor_images_path = os.path.join(vendor_tempdir, "IMAGES")
1378 if not os.path.exists(vendor_images_path):
1379 os.makedirs(vendor_images_path)
1380 with open(os.path.join(vendor_images_path, "system.img"), "w") as output:
1381 pass
1382
Daniel Norman78554ea2021-09-14 10:29:38 -07001383 # Disable care_map.pb as not all ab_partitions are available when
1384 # vendor otatools regenerates vendor images.
Po Hu0663ae42021-09-27 12:59:06 +08001385 if os.path.exists(os.path.join(vendor_tempdir, "META/ab_partitions.txt")):
1386 os.remove(os.path.join(vendor_tempdir, "META/ab_partitions.txt"))
1387 # Disable RADIO images
1388 if os.path.exists(os.path.join(vendor_tempdir, "META/pack_radioimages.txt")):
1389 os.remove(os.path.join(vendor_tempdir, "META/pack_radioimages.txt"))
Daniel Norman78554ea2021-09-14 10:29:38 -07001390
1391 # Build vendor images using vendor otatools.
Iavor-Valentin Iftime63cde0f2022-03-04 16:02:44 +00001392 # Accept either a zip file or extracted directory.
1393 if os.path.isfile(OPTIONS.vendor_otatools):
1394 vendor_otatools_dir = common.MakeTempDir(prefix="vendor_otatools_")
1395 common.UnzipToDir(OPTIONS.vendor_otatools, vendor_otatools_dir)
1396 else:
1397 vendor_otatools_dir = OPTIONS.vendor_otatools
Daniel Norman78554ea2021-09-14 10:29:38 -07001398 cmd = [
1399 os.path.join(vendor_otatools_dir, "bin", "add_img_to_target_files"),
1400 "--is_signing",
Po Hu0663ae42021-09-27 12:59:06 +08001401 "--add_missing",
Daniel Norman78554ea2021-09-14 10:29:38 -07001402 "--verbose",
1403 vendor_tempdir,
1404 ]
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001405 if OPTIONS.rebuild_recovery:
1406 cmd.insert(4, "--rebuild_recovery")
1407
Daniel Norman78554ea2021-09-14 10:29:38 -07001408 common.RunAndCheckOutput(cmd, verbose=True)
1409
1410 logger.info("Writing vendor partitions to output archive.")
1411 with zipfile.ZipFile(
1412 output_zip_path, "a", compression=zipfile.ZIP_DEFLATED,
1413 allowZip64=True) as output_zip:
1414 for p in OPTIONS.vendor_partitions:
Iavor-Valentin Iftime880e4432022-03-17 14:02:27 +00001415 img_file_path = "IMAGES/{}.img".format(p)
1416 map_file_path = "IMAGES/{}.map".format(p)
1417 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, img_file_path), img_file_path)
1418 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, map_file_path), map_file_path)
Iavor-Valentin Iftime40adb172022-04-19 18:17:56 +00001419 # copy recovery.img, boot.img, recovery patch & install.sh
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001420 if OPTIONS.rebuild_recovery:
Iavor-Valentin Iftime40adb172022-04-19 18:17:56 +00001421 recovery_img = "IMAGES/recovery.img"
1422 boot_img = "IMAGES/boot.img"
1423 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, recovery_img), recovery_img)
1424 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, boot_img), boot_img)
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001425 recovery_patch_path = "VENDOR/recovery-from-boot.p"
1426 recovery_sh_path = "VENDOR/bin/install-recovery.sh"
1427 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, recovery_patch_path), recovery_patch_path)
1428 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, recovery_sh_path), recovery_sh_path)
Daniel Norman78554ea2021-09-14 10:29:38 -07001429
1430
Doug Zongkereef39442009-04-02 12:14:19 -07001431def main(argv):
1432
Doug Zongker831840e2011-09-22 10:28:04 -07001433 key_mapping_options = []
1434
Doug Zongkereef39442009-04-02 12:14:19 -07001435 def option_handler(o, a):
Doug Zongker05d3dea2009-06-22 11:32:31 -07001436 if o in ("-e", "--extra_apks"):
Doug Zongkereef39442009-04-02 12:14:19 -07001437 names, key = a.split("=")
1438 names = names.split(",")
1439 for n in names:
1440 OPTIONS.extra_apks[n] = key
Tao Baoaa7e9932019-03-15 09:37:01 -07001441 elif o == "--extra_apex_payload_key":
1442 apex_name, key = a.split("=")
1443 OPTIONS.extra_apex_payload_keys[apex_name] = key
Tao Bao93c2a012018-06-19 12:19:35 -07001444 elif o == "--skip_apks_with_path_prefix":
Tianjiea85bdf02020-07-29 11:56:19 -07001445 # Check the prefix, which must be in all upper case.
Tao Bao93c2a012018-06-19 12:19:35 -07001446 prefix = a.split('/')[0]
1447 if not prefix or prefix != prefix.upper():
1448 raise ValueError("Invalid path prefix '%s'" % (a,))
1449 OPTIONS.skip_apks_with_path_prefix.add(a)
Doug Zongkereef39442009-04-02 12:14:19 -07001450 elif o in ("-d", "--default_key_mappings"):
Doug Zongker831840e2011-09-22 10:28:04 -07001451 key_mapping_options.append((None, a))
Doug Zongkereef39442009-04-02 12:14:19 -07001452 elif o in ("-k", "--key_mapping"):
Doug Zongker831840e2011-09-22 10:28:04 -07001453 key_mapping_options.append(a.split("=", 1))
Doug Zongker8e931bf2009-04-06 15:21:45 -07001454 elif o in ("-o", "--replace_ota_keys"):
1455 OPTIONS.replace_ota_keys = True
Doug Zongkerae877012009-04-21 10:04:51 -07001456 elif o in ("-t", "--tag_changes"):
1457 new = []
1458 for i in a.split(","):
1459 i = i.strip()
1460 if not i or i[0] not in "-+":
1461 raise ValueError("Bad tag change '%s'" % (i,))
1462 new.append(i[0] + i[1:].strip())
1463 OPTIONS.tag_changes = tuple(new)
Geremy Condraf19b3652014-07-29 17:54:54 -07001464 elif o == "--replace_verity_public_key":
1465 OPTIONS.replace_verity_public_key = (True, a)
1466 elif o == "--replace_verity_private_key":
1467 OPTIONS.replace_verity_private_key = (True, a)
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001468 elif o == "--replace_verity_keyid":
1469 OPTIONS.replace_verity_keyid = (True, a)
Bowgo Tsai2fe786a2020-02-21 17:48:18 +08001470 elif o == "--remove_avb_public_keys":
1471 OPTIONS.remove_avb_public_keys = a.split(",")
Tao Bao639118f2017-06-19 15:48:02 -07001472 elif o == "--avb_vbmeta_key":
1473 OPTIONS.avb_keys['vbmeta'] = a
1474 elif o == "--avb_vbmeta_algorithm":
1475 OPTIONS.avb_algorithms['vbmeta'] = a
1476 elif o == "--avb_vbmeta_extra_args":
1477 OPTIONS.avb_extra_args['vbmeta'] = a
1478 elif o == "--avb_boot_key":
1479 OPTIONS.avb_keys['boot'] = a
1480 elif o == "--avb_boot_algorithm":
1481 OPTIONS.avb_algorithms['boot'] = a
1482 elif o == "--avb_boot_extra_args":
1483 OPTIONS.avb_extra_args['boot'] = a
1484 elif o == "--avb_dtbo_key":
1485 OPTIONS.avb_keys['dtbo'] = a
1486 elif o == "--avb_dtbo_algorithm":
1487 OPTIONS.avb_algorithms['dtbo'] = a
1488 elif o == "--avb_dtbo_extra_args":
1489 OPTIONS.avb_extra_args['dtbo'] = a
1490 elif o == "--avb_system_key":
1491 OPTIONS.avb_keys['system'] = a
1492 elif o == "--avb_system_algorithm":
1493 OPTIONS.avb_algorithms['system'] = a
1494 elif o == "--avb_system_extra_args":
1495 OPTIONS.avb_extra_args['system'] = a
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001496 elif o == "--avb_system_other_key":
1497 OPTIONS.avb_keys['system_other'] = a
1498 elif o == "--avb_system_other_algorithm":
1499 OPTIONS.avb_algorithms['system_other'] = a
1500 elif o == "--avb_system_other_extra_args":
1501 OPTIONS.avb_extra_args['system_other'] = a
Tao Bao639118f2017-06-19 15:48:02 -07001502 elif o == "--avb_vendor_key":
1503 OPTIONS.avb_keys['vendor'] = a
1504 elif o == "--avb_vendor_algorithm":
1505 OPTIONS.avb_algorithms['vendor'] = a
1506 elif o == "--avb_vendor_extra_args":
1507 OPTIONS.avb_extra_args['vendor'] = a
Tao Baod6085d62019-05-06 12:55:42 -07001508 elif o == "--avb_vbmeta_system_key":
1509 OPTIONS.avb_keys['vbmeta_system'] = a
1510 elif o == "--avb_vbmeta_system_algorithm":
1511 OPTIONS.avb_algorithms['vbmeta_system'] = a
1512 elif o == "--avb_vbmeta_system_extra_args":
1513 OPTIONS.avb_extra_args['vbmeta_system'] = a
1514 elif o == "--avb_vbmeta_vendor_key":
1515 OPTIONS.avb_keys['vbmeta_vendor'] = a
1516 elif o == "--avb_vbmeta_vendor_algorithm":
1517 OPTIONS.avb_algorithms['vbmeta_vendor'] = a
1518 elif o == "--avb_vbmeta_vendor_extra_args":
1519 OPTIONS.avb_extra_args['vbmeta_vendor'] = a
Tao Baoaa7e9932019-03-15 09:37:01 -07001520 elif o == "--avb_apex_extra_args":
1521 OPTIONS.avb_extra_args['apex'] = a
Hongguang Chenf23364d2020-04-27 18:36:36 -07001522 elif o == "--avb_extra_custom_image_key":
1523 partition, key = a.split("=")
1524 OPTIONS.avb_keys[partition] = key
1525 elif o == "--avb_extra_custom_image_algorithm":
1526 partition, algorithm = a.split("=")
1527 OPTIONS.avb_algorithms[partition] = algorithm
1528 elif o == "--avb_extra_custom_image_extra_args":
Hongguang Chen883eecb2020-05-23 22:20:19 -07001529 # Setting the maxsplit parameter to one, which will return a list with
1530 # two elements. e.g., the second '=' should not be splitted for
1531 # 'oem=--signing_helper_with_files=/tmp/avbsigner.sh'.
1532 partition, extra_args = a.split("=", 1)
Hongguang Chenf23364d2020-04-27 18:36:36 -07001533 OPTIONS.avb_extra_args[partition] = extra_args
Bowgo Tsai27c39b02021-03-12 21:40:32 +08001534 elif o == "--gki_signing_key":
1535 OPTIONS.gki_signing_key = a
1536 elif o == "--gki_signing_algorithm":
1537 OPTIONS.gki_signing_algorithm = a
1538 elif o == "--gki_signing_extra_args":
1539 OPTIONS.gki_signing_extra_args = a
Daniel Norman78554ea2021-09-14 10:29:38 -07001540 elif o == "--vendor_otatools":
1541 OPTIONS.vendor_otatools = a
1542 elif o == "--vendor_partitions":
1543 OPTIONS.vendor_partitions = set(a.split(","))
Melisa Carranza Zunigae6d4fb52022-03-07 14:56:26 +01001544 elif o == '--sepolicy_key':
1545 OPTIONS.sepolicy_key = a
1546 elif o == '--sepolicy_cert':
1547 OPTIONS.sepolicy_cert = a
1548 elif o == '--fsverity_tool':
1549 OPTIONS.fsverity_tool = a
Bowgo Tsai2a781692021-10-13 17:39:33 +08001550 elif o == "--allow_gsi_debug_sepolicy":
1551 OPTIONS.allow_gsi_debug_sepolicy = True
Doug Zongkereef39442009-04-02 12:14:19 -07001552 else:
1553 return False
1554 return True
1555
Tao Bao639118f2017-06-19 15:48:02 -07001556 args = common.ParseOptions(
1557 argv, __doc__,
1558 extra_opts="e:d:k:ot:",
1559 extra_long_opts=[
Tao Bao0c28d2d2017-12-24 10:37:38 -08001560 "extra_apks=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001561 "extra_apex_payload_key=",
Tao Bao93c2a012018-06-19 12:19:35 -07001562 "skip_apks_with_path_prefix=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001563 "default_key_mappings=",
1564 "key_mapping=",
1565 "replace_ota_keys",
1566 "tag_changes=",
1567 "replace_verity_public_key=",
1568 "replace_verity_private_key=",
1569 "replace_verity_keyid=",
Bowgo Tsai2fe786a2020-02-21 17:48:18 +08001570 "remove_avb_public_keys=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001571 "avb_apex_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001572 "avb_vbmeta_algorithm=",
1573 "avb_vbmeta_key=",
1574 "avb_vbmeta_extra_args=",
1575 "avb_boot_algorithm=",
1576 "avb_boot_key=",
1577 "avb_boot_extra_args=",
1578 "avb_dtbo_algorithm=",
1579 "avb_dtbo_key=",
1580 "avb_dtbo_extra_args=",
1581 "avb_system_algorithm=",
1582 "avb_system_key=",
1583 "avb_system_extra_args=",
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001584 "avb_system_other_algorithm=",
1585 "avb_system_other_key=",
1586 "avb_system_other_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001587 "avb_vendor_algorithm=",
1588 "avb_vendor_key=",
1589 "avb_vendor_extra_args=",
Tao Baod6085d62019-05-06 12:55:42 -07001590 "avb_vbmeta_system_algorithm=",
1591 "avb_vbmeta_system_key=",
1592 "avb_vbmeta_system_extra_args=",
1593 "avb_vbmeta_vendor_algorithm=",
1594 "avb_vbmeta_vendor_key=",
1595 "avb_vbmeta_vendor_extra_args=",
Hongguang Chenf23364d2020-04-27 18:36:36 -07001596 "avb_extra_custom_image_key=",
1597 "avb_extra_custom_image_algorithm=",
1598 "avb_extra_custom_image_extra_args=",
Bowgo Tsai27c39b02021-03-12 21:40:32 +08001599 "gki_signing_key=",
1600 "gki_signing_algorithm=",
1601 "gki_signing_extra_args=",
Daniel Norman78554ea2021-09-14 10:29:38 -07001602 "vendor_partitions=",
1603 "vendor_otatools=",
Melisa Carranza Zunigae6d4fb52022-03-07 14:56:26 +01001604 "sepolicy_key=",
1605 "sepolicy_cert=",
1606 "fsverity_tool=",
Bowgo Tsai2a781692021-10-13 17:39:33 +08001607 "allow_gsi_debug_sepolicy",
Tao Bao639118f2017-06-19 15:48:02 -07001608 ],
1609 extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001610
1611 if len(args) != 2:
1612 common.Usage(__doc__)
1613 sys.exit(1)
1614
Tao Baobadceb22019-03-15 09:33:43 -07001615 common.InitLogging()
1616
Kelvin Zhang928c2342020-09-22 16:15:57 -04001617 input_zip = zipfile.ZipFile(args[0], "r", allowZip64=True)
Tao Bao2b8f4892017-06-13 12:54:58 -07001618 output_zip = zipfile.ZipFile(args[1], "w",
1619 compression=zipfile.ZIP_DEFLATED,
1620 allowZip64=True)
Doug Zongkereef39442009-04-02 12:14:19 -07001621
Doug Zongker831840e2011-09-22 10:28:04 -07001622 misc_info = common.LoadInfoDict(input_zip)
1623
1624 BuildKeyMap(misc_info, key_mapping_options)
1625
Tao Baoaa7e9932019-03-15 09:37:01 -07001626 apk_keys_info, compressed_extension = common.ReadApkCerts(input_zip)
1627 apk_keys = GetApkCerts(apk_keys_info)
Doug Zongkereb338ef2009-05-20 16:50:49 -07001628
Melisa Carranza Zunigae6d4fb52022-03-07 14:56:26 +01001629 apex_keys_info, sepolicy_keys_info = ReadApexKeysInfo(input_zip)
Tao Baoaa7e9932019-03-15 09:37:01 -07001630 apex_keys = GetApexKeys(apex_keys_info, apk_keys)
Melisa Carranza Zunigae6d4fb52022-03-07 14:56:26 +01001631 sepolicy_keys = GetSepolicyKeys(sepolicy_keys_info)
Tao Baoaa7e9932019-03-15 09:37:01 -07001632
Tianjie Xu88a759d2020-01-23 10:47:54 -08001633 # TODO(xunchang) check for the apks inside the apex files, and abort early if
1634 # the keys are not available.
Tao Baoaa7e9932019-03-15 09:37:01 -07001635 CheckApkAndApexKeysAvailable(
1636 input_zip,
1637 set(apk_keys.keys()) | set(apex_keys.keys()),
Tao Baoe1343992019-03-19 12:24:03 -07001638 compressed_extension,
1639 apex_keys)
Tao Baoaa7e9932019-03-15 09:37:01 -07001640
1641 key_passwords = common.GetKeyPasswords(
1642 set(apk_keys.values()) | set(itertools.chain(*apex_keys.values())))
Tao Bao9aa4b9b2016-09-29 17:53:56 -07001643 platform_api_level, _ = GetApiLevelAndCodename(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001644 codename_to_api_level_map = GetCodenameToApiLevelMap(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001645
Doug Zongker412c02f2014-02-13 10:58:24 -08001646 ProcessTargetFiles(input_zip, output_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -07001647 apk_keys, apex_keys, key_passwords,
1648 platform_api_level, codename_to_api_level_map,
Melisa Carranza Zunigae6d4fb52022-03-07 14:56:26 +01001649 compressed_extension, sepolicy_keys)
Doug Zongker8e931bf2009-04-06 15:21:45 -07001650
Tao Bao2ed665a2015-04-01 11:21:55 -07001651 common.ZipClose(input_zip)
1652 common.ZipClose(output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001653
Daniel Norman78554ea2021-09-14 10:29:38 -07001654 if OPTIONS.vendor_partitions and OPTIONS.vendor_otatools:
1655 BuildVendorPartitions(args[1])
1656
Tianjie Xub48589a2016-08-03 19:21:52 -07001657 # Skip building userdata.img and cache.img when signing the target files.
Daniel Norman78554ea2021-09-14 10:29:38 -07001658 new_args = ["--is_signing", "--add_missing", "--verbose"]
Tianjie Xu616fbeb2017-05-23 14:51:02 -07001659 # add_img_to_target_files builds the system image from scratch, so the
1660 # recovery patch is guaranteed to be regenerated there.
1661 if OPTIONS.rebuild_recovery:
1662 new_args.append("--rebuild_recovery")
1663 new_args.append(args[1])
Tianjie Xub48589a2016-08-03 19:21:52 -07001664 add_img_to_target_files.main(new_args)
Doug Zongker3c84f562014-07-31 11:06:30 -07001665
Tao Bao0c28d2d2017-12-24 10:37:38 -08001666 print("done.")
Doug Zongkereef39442009-04-02 12:14:19 -07001667
1668
1669if __name__ == '__main__':
1670 try:
1671 main(sys.argv[1:])
Tao Bao639118f2017-06-19 15:48:02 -07001672 finally:
1673 common.Cleanup()