blob: 6af748664cd02c347bdabb89e27cdac2dcdd5cae [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
1358
Daniel Norman78554ea2021-09-14 10:29:38 -07001359 vendor_misc_info["board_bpt_enable"] = "false" # partition-table
1360 vendor_misc_info["has_dtbo"] = "false" # dtbo
1361 vendor_misc_info["has_pvmfw"] = "false" # pvmfw
1362 vendor_misc_info["avb_custom_images_partition_list"] = "" # custom images
1363 vendor_misc_info["avb_enable"] = "false" # vbmeta
1364 vendor_misc_info["use_dynamic_partitions"] = "false" # super_empty
1365 vendor_misc_info["build_super_partition"] = "false" # super split
1366 with open(vendor_misc_info_path, "w") as output:
1367 for key in sorted(vendor_misc_info):
1368 output.write("{}={}\n".format(key, vendor_misc_info[key]))
1369
Po Hu0663ae42021-09-27 12:59:06 +08001370 # Disable system partition by a placeholder of IMAGES/system.img,
1371 # instead of removing SYSTEM folder.
1372 # Because SYSTEM/build.prop is still needed for:
1373 # add_img_to_target_files.CreateImage ->
1374 # common.BuildInfo ->
1375 # common.BuildInfo.CalculateFingerprint
1376 vendor_images_path = os.path.join(vendor_tempdir, "IMAGES")
1377 if not os.path.exists(vendor_images_path):
1378 os.makedirs(vendor_images_path)
1379 with open(os.path.join(vendor_images_path, "system.img"), "w") as output:
1380 pass
1381
Daniel Norman78554ea2021-09-14 10:29:38 -07001382 # Disable care_map.pb as not all ab_partitions are available when
1383 # vendor otatools regenerates vendor images.
Po Hu0663ae42021-09-27 12:59:06 +08001384 if os.path.exists(os.path.join(vendor_tempdir, "META/ab_partitions.txt")):
1385 os.remove(os.path.join(vendor_tempdir, "META/ab_partitions.txt"))
1386 # Disable RADIO images
1387 if os.path.exists(os.path.join(vendor_tempdir, "META/pack_radioimages.txt")):
1388 os.remove(os.path.join(vendor_tempdir, "META/pack_radioimages.txt"))
Daniel Norman78554ea2021-09-14 10:29:38 -07001389
1390 # Build vendor images using vendor otatools.
Iavor-Valentin Iftime63cde0f2022-03-04 16:02:44 +00001391 # Accept either a zip file or extracted directory.
1392 if os.path.isfile(OPTIONS.vendor_otatools):
1393 vendor_otatools_dir = common.MakeTempDir(prefix="vendor_otatools_")
1394 common.UnzipToDir(OPTIONS.vendor_otatools, vendor_otatools_dir)
1395 else:
1396 vendor_otatools_dir = OPTIONS.vendor_otatools
Daniel Norman78554ea2021-09-14 10:29:38 -07001397 cmd = [
1398 os.path.join(vendor_otatools_dir, "bin", "add_img_to_target_files"),
1399 "--is_signing",
Po Hu0663ae42021-09-27 12:59:06 +08001400 "--add_missing",
Daniel Norman78554ea2021-09-14 10:29:38 -07001401 "--verbose",
1402 vendor_tempdir,
1403 ]
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001404 if OPTIONS.rebuild_recovery:
1405 cmd.insert(4, "--rebuild_recovery")
1406
Daniel Norman78554ea2021-09-14 10:29:38 -07001407 common.RunAndCheckOutput(cmd, verbose=True)
1408
1409 logger.info("Writing vendor partitions to output archive.")
1410 with zipfile.ZipFile(
1411 output_zip_path, "a", compression=zipfile.ZIP_DEFLATED,
1412 allowZip64=True) as output_zip:
1413 for p in OPTIONS.vendor_partitions:
Iavor-Valentin Iftime880e4432022-03-17 14:02:27 +00001414 img_file_path = "IMAGES/{}.img".format(p)
1415 map_file_path = "IMAGES/{}.map".format(p)
1416 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, img_file_path), img_file_path)
1417 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, map_file_path), map_file_path)
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001418 # copy recovery patch & install.sh
1419 if OPTIONS.rebuild_recovery:
1420 recovery_patch_path = "VENDOR/recovery-from-boot.p"
1421 recovery_sh_path = "VENDOR/bin/install-recovery.sh"
1422 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, recovery_patch_path), recovery_patch_path)
1423 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, recovery_sh_path), recovery_sh_path)
Daniel Norman78554ea2021-09-14 10:29:38 -07001424
1425
Doug Zongkereef39442009-04-02 12:14:19 -07001426def main(argv):
1427
Doug Zongker831840e2011-09-22 10:28:04 -07001428 key_mapping_options = []
1429
Doug Zongkereef39442009-04-02 12:14:19 -07001430 def option_handler(o, a):
Doug Zongker05d3dea2009-06-22 11:32:31 -07001431 if o in ("-e", "--extra_apks"):
Doug Zongkereef39442009-04-02 12:14:19 -07001432 names, key = a.split("=")
1433 names = names.split(",")
1434 for n in names:
1435 OPTIONS.extra_apks[n] = key
Tao Baoaa7e9932019-03-15 09:37:01 -07001436 elif o == "--extra_apex_payload_key":
1437 apex_name, key = a.split("=")
1438 OPTIONS.extra_apex_payload_keys[apex_name] = key
Tao Bao93c2a012018-06-19 12:19:35 -07001439 elif o == "--skip_apks_with_path_prefix":
Tianjiea85bdf02020-07-29 11:56:19 -07001440 # Check the prefix, which must be in all upper case.
Tao Bao93c2a012018-06-19 12:19:35 -07001441 prefix = a.split('/')[0]
1442 if not prefix or prefix != prefix.upper():
1443 raise ValueError("Invalid path prefix '%s'" % (a,))
1444 OPTIONS.skip_apks_with_path_prefix.add(a)
Doug Zongkereef39442009-04-02 12:14:19 -07001445 elif o in ("-d", "--default_key_mappings"):
Doug Zongker831840e2011-09-22 10:28:04 -07001446 key_mapping_options.append((None, a))
Doug Zongkereef39442009-04-02 12:14:19 -07001447 elif o in ("-k", "--key_mapping"):
Doug Zongker831840e2011-09-22 10:28:04 -07001448 key_mapping_options.append(a.split("=", 1))
Doug Zongker8e931bf2009-04-06 15:21:45 -07001449 elif o in ("-o", "--replace_ota_keys"):
1450 OPTIONS.replace_ota_keys = True
Doug Zongkerae877012009-04-21 10:04:51 -07001451 elif o in ("-t", "--tag_changes"):
1452 new = []
1453 for i in a.split(","):
1454 i = i.strip()
1455 if not i or i[0] not in "-+":
1456 raise ValueError("Bad tag change '%s'" % (i,))
1457 new.append(i[0] + i[1:].strip())
1458 OPTIONS.tag_changes = tuple(new)
Geremy Condraf19b3652014-07-29 17:54:54 -07001459 elif o == "--replace_verity_public_key":
1460 OPTIONS.replace_verity_public_key = (True, a)
1461 elif o == "--replace_verity_private_key":
1462 OPTIONS.replace_verity_private_key = (True, a)
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001463 elif o == "--replace_verity_keyid":
1464 OPTIONS.replace_verity_keyid = (True, a)
Bowgo Tsai2fe786a2020-02-21 17:48:18 +08001465 elif o == "--remove_avb_public_keys":
1466 OPTIONS.remove_avb_public_keys = a.split(",")
Tao Bao639118f2017-06-19 15:48:02 -07001467 elif o == "--avb_vbmeta_key":
1468 OPTIONS.avb_keys['vbmeta'] = a
1469 elif o == "--avb_vbmeta_algorithm":
1470 OPTIONS.avb_algorithms['vbmeta'] = a
1471 elif o == "--avb_vbmeta_extra_args":
1472 OPTIONS.avb_extra_args['vbmeta'] = a
1473 elif o == "--avb_boot_key":
1474 OPTIONS.avb_keys['boot'] = a
1475 elif o == "--avb_boot_algorithm":
1476 OPTIONS.avb_algorithms['boot'] = a
1477 elif o == "--avb_boot_extra_args":
1478 OPTIONS.avb_extra_args['boot'] = a
1479 elif o == "--avb_dtbo_key":
1480 OPTIONS.avb_keys['dtbo'] = a
1481 elif o == "--avb_dtbo_algorithm":
1482 OPTIONS.avb_algorithms['dtbo'] = a
1483 elif o == "--avb_dtbo_extra_args":
1484 OPTIONS.avb_extra_args['dtbo'] = a
1485 elif o == "--avb_system_key":
1486 OPTIONS.avb_keys['system'] = a
1487 elif o == "--avb_system_algorithm":
1488 OPTIONS.avb_algorithms['system'] = a
1489 elif o == "--avb_system_extra_args":
1490 OPTIONS.avb_extra_args['system'] = a
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001491 elif o == "--avb_system_other_key":
1492 OPTIONS.avb_keys['system_other'] = a
1493 elif o == "--avb_system_other_algorithm":
1494 OPTIONS.avb_algorithms['system_other'] = a
1495 elif o == "--avb_system_other_extra_args":
1496 OPTIONS.avb_extra_args['system_other'] = a
Tao Bao639118f2017-06-19 15:48:02 -07001497 elif o == "--avb_vendor_key":
1498 OPTIONS.avb_keys['vendor'] = a
1499 elif o == "--avb_vendor_algorithm":
1500 OPTIONS.avb_algorithms['vendor'] = a
1501 elif o == "--avb_vendor_extra_args":
1502 OPTIONS.avb_extra_args['vendor'] = a
Tao Baod6085d62019-05-06 12:55:42 -07001503 elif o == "--avb_vbmeta_system_key":
1504 OPTIONS.avb_keys['vbmeta_system'] = a
1505 elif o == "--avb_vbmeta_system_algorithm":
1506 OPTIONS.avb_algorithms['vbmeta_system'] = a
1507 elif o == "--avb_vbmeta_system_extra_args":
1508 OPTIONS.avb_extra_args['vbmeta_system'] = a
1509 elif o == "--avb_vbmeta_vendor_key":
1510 OPTIONS.avb_keys['vbmeta_vendor'] = a
1511 elif o == "--avb_vbmeta_vendor_algorithm":
1512 OPTIONS.avb_algorithms['vbmeta_vendor'] = a
1513 elif o == "--avb_vbmeta_vendor_extra_args":
1514 OPTIONS.avb_extra_args['vbmeta_vendor'] = a
Tao Baoaa7e9932019-03-15 09:37:01 -07001515 elif o == "--avb_apex_extra_args":
1516 OPTIONS.avb_extra_args['apex'] = a
Hongguang Chenf23364d2020-04-27 18:36:36 -07001517 elif o == "--avb_extra_custom_image_key":
1518 partition, key = a.split("=")
1519 OPTIONS.avb_keys[partition] = key
1520 elif o == "--avb_extra_custom_image_algorithm":
1521 partition, algorithm = a.split("=")
1522 OPTIONS.avb_algorithms[partition] = algorithm
1523 elif o == "--avb_extra_custom_image_extra_args":
Hongguang Chen883eecb2020-05-23 22:20:19 -07001524 # Setting the maxsplit parameter to one, which will return a list with
1525 # two elements. e.g., the second '=' should not be splitted for
1526 # 'oem=--signing_helper_with_files=/tmp/avbsigner.sh'.
1527 partition, extra_args = a.split("=", 1)
Hongguang Chenf23364d2020-04-27 18:36:36 -07001528 OPTIONS.avb_extra_args[partition] = extra_args
Bowgo Tsai27c39b02021-03-12 21:40:32 +08001529 elif o == "--gki_signing_key":
1530 OPTIONS.gki_signing_key = a
1531 elif o == "--gki_signing_algorithm":
1532 OPTIONS.gki_signing_algorithm = a
1533 elif o == "--gki_signing_extra_args":
1534 OPTIONS.gki_signing_extra_args = a
Daniel Norman78554ea2021-09-14 10:29:38 -07001535 elif o == "--vendor_otatools":
1536 OPTIONS.vendor_otatools = a
1537 elif o == "--vendor_partitions":
1538 OPTIONS.vendor_partitions = set(a.split(","))
Melisa Carranza Zunigae6d4fb52022-03-07 14:56:26 +01001539 elif o == '--sepolicy_key':
1540 OPTIONS.sepolicy_key = a
1541 elif o == '--sepolicy_cert':
1542 OPTIONS.sepolicy_cert = a
1543 elif o == '--fsverity_tool':
1544 OPTIONS.fsverity_tool = a
Bowgo Tsai2a781692021-10-13 17:39:33 +08001545 elif o == "--allow_gsi_debug_sepolicy":
1546 OPTIONS.allow_gsi_debug_sepolicy = True
Doug Zongkereef39442009-04-02 12:14:19 -07001547 else:
1548 return False
1549 return True
1550
Tao Bao639118f2017-06-19 15:48:02 -07001551 args = common.ParseOptions(
1552 argv, __doc__,
1553 extra_opts="e:d:k:ot:",
1554 extra_long_opts=[
Tao Bao0c28d2d2017-12-24 10:37:38 -08001555 "extra_apks=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001556 "extra_apex_payload_key=",
Tao Bao93c2a012018-06-19 12:19:35 -07001557 "skip_apks_with_path_prefix=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001558 "default_key_mappings=",
1559 "key_mapping=",
1560 "replace_ota_keys",
1561 "tag_changes=",
1562 "replace_verity_public_key=",
1563 "replace_verity_private_key=",
1564 "replace_verity_keyid=",
Bowgo Tsai2fe786a2020-02-21 17:48:18 +08001565 "remove_avb_public_keys=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001566 "avb_apex_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001567 "avb_vbmeta_algorithm=",
1568 "avb_vbmeta_key=",
1569 "avb_vbmeta_extra_args=",
1570 "avb_boot_algorithm=",
1571 "avb_boot_key=",
1572 "avb_boot_extra_args=",
1573 "avb_dtbo_algorithm=",
1574 "avb_dtbo_key=",
1575 "avb_dtbo_extra_args=",
1576 "avb_system_algorithm=",
1577 "avb_system_key=",
1578 "avb_system_extra_args=",
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001579 "avb_system_other_algorithm=",
1580 "avb_system_other_key=",
1581 "avb_system_other_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001582 "avb_vendor_algorithm=",
1583 "avb_vendor_key=",
1584 "avb_vendor_extra_args=",
Tao Baod6085d62019-05-06 12:55:42 -07001585 "avb_vbmeta_system_algorithm=",
1586 "avb_vbmeta_system_key=",
1587 "avb_vbmeta_system_extra_args=",
1588 "avb_vbmeta_vendor_algorithm=",
1589 "avb_vbmeta_vendor_key=",
1590 "avb_vbmeta_vendor_extra_args=",
Hongguang Chenf23364d2020-04-27 18:36:36 -07001591 "avb_extra_custom_image_key=",
1592 "avb_extra_custom_image_algorithm=",
1593 "avb_extra_custom_image_extra_args=",
Bowgo Tsai27c39b02021-03-12 21:40:32 +08001594 "gki_signing_key=",
1595 "gki_signing_algorithm=",
1596 "gki_signing_extra_args=",
Daniel Norman78554ea2021-09-14 10:29:38 -07001597 "vendor_partitions=",
1598 "vendor_otatools=",
Melisa Carranza Zunigae6d4fb52022-03-07 14:56:26 +01001599 "sepolicy_key=",
1600 "sepolicy_cert=",
1601 "fsverity_tool=",
Bowgo Tsai2a781692021-10-13 17:39:33 +08001602 "allow_gsi_debug_sepolicy",
Tao Bao639118f2017-06-19 15:48:02 -07001603 ],
1604 extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001605
1606 if len(args) != 2:
1607 common.Usage(__doc__)
1608 sys.exit(1)
1609
Tao Baobadceb22019-03-15 09:33:43 -07001610 common.InitLogging()
1611
Kelvin Zhang928c2342020-09-22 16:15:57 -04001612 input_zip = zipfile.ZipFile(args[0], "r", allowZip64=True)
Tao Bao2b8f4892017-06-13 12:54:58 -07001613 output_zip = zipfile.ZipFile(args[1], "w",
1614 compression=zipfile.ZIP_DEFLATED,
1615 allowZip64=True)
Doug Zongkereef39442009-04-02 12:14:19 -07001616
Doug Zongker831840e2011-09-22 10:28:04 -07001617 misc_info = common.LoadInfoDict(input_zip)
1618
1619 BuildKeyMap(misc_info, key_mapping_options)
1620
Tao Baoaa7e9932019-03-15 09:37:01 -07001621 apk_keys_info, compressed_extension = common.ReadApkCerts(input_zip)
1622 apk_keys = GetApkCerts(apk_keys_info)
Doug Zongkereb338ef2009-05-20 16:50:49 -07001623
Melisa Carranza Zunigae6d4fb52022-03-07 14:56:26 +01001624 apex_keys_info, sepolicy_keys_info = ReadApexKeysInfo(input_zip)
Tao Baoaa7e9932019-03-15 09:37:01 -07001625 apex_keys = GetApexKeys(apex_keys_info, apk_keys)
Melisa Carranza Zunigae6d4fb52022-03-07 14:56:26 +01001626 sepolicy_keys = GetSepolicyKeys(sepolicy_keys_info)
Tao Baoaa7e9932019-03-15 09:37:01 -07001627
Tianjie Xu88a759d2020-01-23 10:47:54 -08001628 # TODO(xunchang) check for the apks inside the apex files, and abort early if
1629 # the keys are not available.
Tao Baoaa7e9932019-03-15 09:37:01 -07001630 CheckApkAndApexKeysAvailable(
1631 input_zip,
1632 set(apk_keys.keys()) | set(apex_keys.keys()),
Tao Baoe1343992019-03-19 12:24:03 -07001633 compressed_extension,
1634 apex_keys)
Tao Baoaa7e9932019-03-15 09:37:01 -07001635
1636 key_passwords = common.GetKeyPasswords(
1637 set(apk_keys.values()) | set(itertools.chain(*apex_keys.values())))
Tao Bao9aa4b9b2016-09-29 17:53:56 -07001638 platform_api_level, _ = GetApiLevelAndCodename(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001639 codename_to_api_level_map = GetCodenameToApiLevelMap(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001640
Doug Zongker412c02f2014-02-13 10:58:24 -08001641 ProcessTargetFiles(input_zip, output_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -07001642 apk_keys, apex_keys, key_passwords,
1643 platform_api_level, codename_to_api_level_map,
Melisa Carranza Zunigae6d4fb52022-03-07 14:56:26 +01001644 compressed_extension, sepolicy_keys)
Doug Zongker8e931bf2009-04-06 15:21:45 -07001645
Tao Bao2ed665a2015-04-01 11:21:55 -07001646 common.ZipClose(input_zip)
1647 common.ZipClose(output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001648
Daniel Norman78554ea2021-09-14 10:29:38 -07001649 if OPTIONS.vendor_partitions and OPTIONS.vendor_otatools:
1650 BuildVendorPartitions(args[1])
1651
Tianjie Xub48589a2016-08-03 19:21:52 -07001652 # Skip building userdata.img and cache.img when signing the target files.
Daniel Norman78554ea2021-09-14 10:29:38 -07001653 new_args = ["--is_signing", "--add_missing", "--verbose"]
Tianjie Xu616fbeb2017-05-23 14:51:02 -07001654 # add_img_to_target_files builds the system image from scratch, so the
1655 # recovery patch is guaranteed to be regenerated there.
1656 if OPTIONS.rebuild_recovery:
1657 new_args.append("--rebuild_recovery")
1658 new_args.append(args[1])
Tianjie Xub48589a2016-08-03 19:21:52 -07001659 add_img_to_target_files.main(new_args)
Doug Zongker3c84f562014-07-31 11:06:30 -07001660
Tao Bao0c28d2d2017-12-24 10:37:38 -08001661 print("done.")
Doug Zongkereef39442009-04-02 12:14:19 -07001662
1663
1664if __name__ == '__main__':
1665 try:
1666 main(sys.argv[1:])
Tao Bao639118f2017-06-19 15:48:02 -07001667 finally:
1668 common.Cleanup()