blob: c595bb80552622ba67f704daa013f4178a79f901 [file] [log] [blame]
Doug Zongkereef39442009-04-02 12:14:19 -07001#!/usr/bin/env python
2#
3# Copyright (C) 2008 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17"""
18Signs all the APK files in a target-files zipfile, producing a new
19target-files zip.
20
21Usage: sign_target_files_apks [flags] input_target_files output_target_files
22
Doug Zongkereef39442009-04-02 12:14:19 -070023 -e (--extra_apks) <name,name,...=key>
Tao Baoaa7e9932019-03-15 09:37:01 -070024 Add extra APK/APEX name/key pairs as though they appeared in apkcerts.txt
25 or apexkeys.txt (so mappings specified by -k and -d are applied). Keys
26 specified in -e override any value for that app contained in the
27 apkcerts.txt file, or the container key for an APEX. Option may be
28 repeated to give multiple extra packages.
29
Kelvin Zhang085b6f32022-07-25 16:12:30 -070030 --extra_apex_payload_key <name,name,...=key>
Tao Baoaa7e9932019-03-15 09:37:01 -070031 Add a mapping for APEX package name to payload signing key, which will
32 override the default payload signing key in apexkeys.txt. Note that the
33 container key should be overridden via the `--extra_apks` flag above.
34 Option may be repeated for multiple APEXes.
Doug Zongkereef39442009-04-02 12:14:19 -070035
Tao Bao93c2a012018-06-19 12:19:35 -070036 --skip_apks_with_path_prefix <prefix>
37 Skip signing an APK if it has the matching prefix in its path. The prefix
38 should be matching the entry name, which has partition names in upper
39 case, e.g. "VENDOR/app/", or "SYSTEM_OTHER/preloads/". Option may be
40 repeated to give multiple prefixes.
41
Doug Zongkereef39442009-04-02 12:14:19 -070042 -k (--key_mapping) <src_key=dest_key>
43 Add a mapping from the key name as specified in apkcerts.txt (the
44 src_key) to the real key you wish to sign the package with
45 (dest_key). Option may be repeated to give multiple key
46 mappings.
47
48 -d (--default_key_mappings) <dir>
49 Set up the following key mappings:
50
Doug Zongker831840e2011-09-22 10:28:04 -070051 $devkey/devkey ==> $dir/releasekey
52 $devkey/testkey ==> $dir/releasekey
53 $devkey/media ==> $dir/media
54 $devkey/shared ==> $dir/shared
55 $devkey/platform ==> $dir/platform
56
57 where $devkey is the directory part of the value of
58 default_system_dev_certificate from the input target-files's
Dan Willemsen0ab1be62019-04-09 21:35:37 -070059 META/misc_info.txt. (Defaulting to "build/make/target/product/security"
Doug Zongker831840e2011-09-22 10:28:04 -070060 if the value is not present in misc_info.
Doug Zongkereef39442009-04-02 12:14:19 -070061
62 -d and -k options are added to the set of mappings in the order
63 in which they appear on the command line.
Doug Zongker8e931bf2009-04-06 15:21:45 -070064
65 -o (--replace_ota_keys)
Tao Baoa80ed222016-06-16 14:41:24 -070066 Replace the certificate (public key) used by OTA package verification
67 with the ones specified in the input target_files zip (in the
68 META/otakeys.txt file). Key remapping (-k and -d) is performed on the
69 keys. For A/B devices, the payload verification key will be replaced
70 as well. If there're multiple OTA keys, only the first one will be used
71 for payload verification.
Doug Zongker17aa9442009-04-17 10:15:58 -070072
Doug Zongkerae877012009-04-21 10:04:51 -070073 -t (--tag_changes) <+tag>,<-tag>,...
74 Comma-separated list of changes to make to the set of tags (in
75 the last component of the build fingerprint). Prefix each with
76 '+' or '-' to indicate whether that tag should be added or
77 removed. Changes are processed in the order they appear.
Doug Zongker831840e2011-09-22 10:28:04 -070078 Default value is "-test-keys,-dev-keys,+release-keys".
Doug Zongkerae877012009-04-21 10:04:51 -070079
Tao Bao8adcfd12016-06-17 17:01:22 -070080 --replace_verity_private_key <key>
81 Replace the private key used for verity signing. It expects a filename
82 WITHOUT the extension (e.g. verity_key).
83
84 --replace_verity_public_key <key>
85 Replace the certificate (public key) used for verity verification. The
86 key file replaces the one at BOOT/RAMDISK/verity_key (or ROOT/verity_key
87 for devices using system_root_image). It expects the key filename WITH
88 the extension (e.g. verity_key.pub).
89
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -070090 --replace_verity_keyid <path_to_X509_PEM_cert_file>
91 Replace the veritykeyid in BOOT/cmdline of input_target_file_zip
Tao Bao8adcfd12016-06-17 17:01:22 -070092 with keyid of the cert pointed by <path_to_X509_PEM_cert_file>.
Tao Bao639118f2017-06-19 15:48:02 -070093
Bowgo Tsai2fe786a2020-02-21 17:48:18 +080094 --remove_avb_public_keys <key1>,<key2>,...
95 Remove AVB public keys from the first-stage ramdisk. The key file to
96 remove is located at either of the following dirs:
97 - BOOT/RAMDISK/avb/ or
98 - BOOT/RAMDISK/first_stage_ramdisk/avb/
99 The second dir will be used for lookup if BOARD_USES_RECOVERY_AS_BOOT is
100 set to true.
101
Hongguang Chen0d6b7272022-11-07 13:36:38 -0800102 --avb_{boot,init_boot,recovery,system,system_other,vendor,dtbo,vbmeta,
103 vbmeta_system,vbmeta_vendor}_algorithm <algorithm>
104 --avb_{boot,init_boot,recovery,system,system_other,vendor,dtbo,vbmeta,
105 vbmeta_system,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
Hongguang Chen0d6b7272022-11-07 13:36:38 -0800109 --avb_{apex,init_boot,boot,recovery,system,system_other,vendor,dtbo,vbmeta,
Ben Fennema6082d0a2021-12-11 14:03:10 -0800110 vbmeta_system,vbmeta_vendor}_extra_args <args>
Tao Bao639118f2017-06-19 15:48:02 -0700111 Specify any additional args that are needed to AVB-sign the image
112 (e.g. "--signing_helper /path/to/helper"). The args will be appended to
113 the existing ones in info dict.
Tianjie Xu88a759d2020-01-23 10:47:54 -0800114
Hongguang Chenf23364d2020-04-27 18:36:36 -0700115 --avb_extra_custom_image_key <partition=key>
116 --avb_extra_custom_image_algorithm <partition=algorithm>
117 Use the specified algorithm (e.g. SHA256_RSA4096) and the key to AVB-sign
118 the specified custom images mounted on the partition. Otherwise it uses
119 the existing values in info dict.
120
121 --avb_extra_custom_image_extra_args <partition=extra_args>
122 Specify any additional args that are needed to AVB-sign the custom images
123 mounted on the partition (e.g. "--signing_helper /path/to/helper"). The
124 args will be appended to the existing ones in info dict.
125
Bowgo Tsai27c39b02021-03-12 21:40:32 +0800126 --gki_signing_algorithm <algorithm>
127 --gki_signing_key <key>
128 Use the specified algorithm (e.g. SHA256_RSA4096) and the key to generate
129 'boot signature' in a v4 boot.img. Otherwise it uses the existing values
130 in info dict.
131
132 --gki_signing_extra_args <args>
133 Specify any additional args that are needed to generate 'boot signature'
134 (e.g. --prop foo:bar). The args will be appended to the existing ones
135 in info dict.
136
Tianjie Xu88a759d2020-01-23 10:47:54 -0800137 --android_jar_path <path>
138 Path to the android.jar to repack the apex file.
Bowgo Tsai2a781692021-10-13 17:39:33 +0800139
140 --allow_gsi_debug_sepolicy
141 Allow the existence of the file 'userdebug_plat_sepolicy.cil' under
142 (/system/system_ext|/system_ext)/etc/selinux.
143 If not set, error out when the file exists.
Kelvin Zhange50bb512022-08-01 15:58:51 -0700144
145 --override_apk_keys <path>
146 Replace all APK keys with this private key
147
148 --override_apex_keys <path>
149 Replace all APEX keys with this private key
Kelvin Zhangb84d2aa2023-11-06 10:53:41 -0800150
151 -k (--package_key) <key>
152 Key to use to sign the package (default is the value of
153 default_system_dev_certificate from the input target-files's
154 META/misc_info.txt, or "build/make/target/product/security/testkey" if
155 that value is not specified).
156
157 For incremental OTAs, the default value is based on the source
158 target-file, not the target build.
159
160 --payload_signer <signer>
161 Specify the signer when signing the payload and metadata for A/B OTAs.
162 By default (i.e. without this flag), it calls 'openssl pkeyutl' to sign
163 with the package private key. If the private key cannot be accessed
164 directly, a payload signer that knows how to do that should be specified.
165 The signer will be supplied with "-inkey <path_to_key>",
166 "-in <input_file>" and "-out <output_file>" parameters.
167
168 --payload_signer_args <args>
169 Specify the arguments needed for payload signer.
170
171 --payload_signer_maximum_signature_size <signature_size>
172 The maximum signature size (in bytes) that would be generated by the given
173 payload signer. Only meaningful when custom payload signer is specified
174 via '--payload_signer'.
175 If the signer uses a RSA key, this should be the number of bytes to
176 represent the modulus. If it uses an EC key, this is the size of a
177 DER-encoded ECDSA signature.
Doug Zongkereef39442009-04-02 12:14:19 -0700178"""
179
Tao Bao0c28d2d2017-12-24 10:37:38 -0800180from __future__ import print_function
Doug Zongkereef39442009-04-02 12:14:19 -0700181
Robert Craig817c5742013-04-19 10:59:22 -0400182import base64
Doug Zongker8e931bf2009-04-06 15:21:45 -0700183import copy
Robert Craig817c5742013-04-19 10:59:22 -0400184import errno
Narayan Kamatha07bf042017-08-14 14:49:21 +0100185import gzip
Tao Baobb733882019-07-24 23:31:19 -0700186import io
Tao Baoaa7e9932019-03-15 09:37:01 -0700187import itertools
Tao Baobadceb22019-03-15 09:33:43 -0700188import logging
Doug Zongkereef39442009-04-02 12:14:19 -0700189import os
190import re
Narayan Kamatha07bf042017-08-14 14:49:21 +0100191import shutil
Tao Bao9fdd00f2017-07-12 11:57:05 -0700192import stat
Tao Bao0c28d2d2017-12-24 10:37:38 -0800193import sys
Doug Zongkereef39442009-04-02 12:14:19 -0700194import tempfile
195import zipfile
Tao Bao66472632017-12-04 17:16:36 -0800196from xml.etree import ElementTree
Doug Zongkereef39442009-04-02 12:14:19 -0700197
Doug Zongker3c84f562014-07-31 11:06:30 -0700198import add_img_to_target_files
Tao Baoaa7e9932019-03-15 09:37:01 -0700199import apex_utils
Doug Zongkereef39442009-04-02 12:14:19 -0700200import common
Kelvin Zhangb84d2aa2023-11-06 10:53:41 -0800201import payload_signer
202from payload_signer import SignOtaPackage, PAYLOAD_BIN
Doug Zongkereef39442009-04-02 12:14:19 -0700203
Tao Bao0c28d2d2017-12-24 10:37:38 -0800204
205if sys.hexversion < 0x02070000:
206 print("Python 2.7 or newer is required.", file=sys.stderr)
207 sys.exit(1)
208
209
Tao Baobadceb22019-03-15 09:33:43 -0700210logger = logging.getLogger(__name__)
211
Doug Zongkereef39442009-04-02 12:14:19 -0700212OPTIONS = common.OPTIONS
213
214OPTIONS.extra_apks = {}
Tao Baoaa7e9932019-03-15 09:37:01 -0700215OPTIONS.extra_apex_payload_keys = {}
Tao Bao93c2a012018-06-19 12:19:35 -0700216OPTIONS.skip_apks_with_path_prefix = set()
Doug Zongkereef39442009-04-02 12:14:19 -0700217OPTIONS.key_map = {}
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700218OPTIONS.rebuild_recovery = False
Doug Zongker8e931bf2009-04-06 15:21:45 -0700219OPTIONS.replace_ota_keys = False
Bowgo Tsai2fe786a2020-02-21 17:48:18 +0800220OPTIONS.remove_avb_public_keys = None
Doug Zongker831840e2011-09-22 10:28:04 -0700221OPTIONS.tag_changes = ("-test-keys", "-dev-keys", "+release-keys")
Tao Bao639118f2017-06-19 15:48:02 -0700222OPTIONS.avb_keys = {}
223OPTIONS.avb_algorithms = {}
224OPTIONS.avb_extra_args = {}
Bowgo Tsai27c39b02021-03-12 21:40:32 +0800225OPTIONS.gki_signing_key = None
226OPTIONS.gki_signing_algorithm = None
227OPTIONS.gki_signing_extra_args = None
Tianjie Xu88a759d2020-01-23 10:47:54 -0800228OPTIONS.android_jar_path = None
Daniel Norman78554ea2021-09-14 10:29:38 -0700229OPTIONS.vendor_partitions = set()
230OPTIONS.vendor_otatools = None
Bowgo Tsai2a781692021-10-13 17:39:33 +0800231OPTIONS.allow_gsi_debug_sepolicy = False
Kelvin Zhange50bb512022-08-01 15:58:51 -0700232OPTIONS.override_apk_keys = None
233OPTIONS.override_apex_keys = None
Doug Zongkereef39442009-04-02 12:14:19 -0700234
Tao Bao0c28d2d2017-12-24 10:37:38 -0800235
Tao Bao19b02fe2019-10-09 00:04:28 -0700236AVB_FOOTER_ARGS_BY_PARTITION = {
Tianjiebf0b8a82021-03-03 17:31:04 -0800237 'boot': 'avb_boot_add_hash_footer_args',
Devin Mooreafdd7c72021-12-13 22:04:08 +0000238 'init_boot': 'avb_init_boot_add_hash_footer_args',
Tianjiebf0b8a82021-03-03 17:31:04 -0800239 'dtbo': 'avb_dtbo_add_hash_footer_args',
240 'product': 'avb_product_add_hashtree_footer_args',
241 'recovery': 'avb_recovery_add_hash_footer_args',
242 'system': 'avb_system_add_hashtree_footer_args',
Ramji Jiyani13a41372022-01-27 07:05:08 +0000243 'system_dlkm': "avb_system_dlkm_add_hashtree_footer_args",
Tianjiebf0b8a82021-03-03 17:31:04 -0800244 'system_ext': 'avb_system_ext_add_hashtree_footer_args',
245 'system_other': 'avb_system_other_add_hashtree_footer_args',
246 'odm': 'avb_odm_add_hashtree_footer_args',
247 'odm_dlkm': 'avb_odm_dlkm_add_hashtree_footer_args',
248 'pvmfw': 'avb_pvmfw_add_hash_footer_args',
249 'vendor': 'avb_vendor_add_hashtree_footer_args',
250 'vendor_boot': 'avb_vendor_boot_add_hash_footer_args',
Lucas Wei03230252022-04-18 16:00:40 +0800251 'vendor_kernel_boot': 'avb_vendor_kernel_boot_add_hash_footer_args',
Tianjiebf0b8a82021-03-03 17:31:04 -0800252 'vendor_dlkm': "avb_vendor_dlkm_add_hashtree_footer_args",
253 'vbmeta': 'avb_vbmeta_args',
254 'vbmeta_system': 'avb_vbmeta_system_args',
255 'vbmeta_vendor': 'avb_vbmeta_vendor_args',
Tao Bao19b02fe2019-10-09 00:04:28 -0700256}
257
258
Tianjiebf0b8a82021-03-03 17:31:04 -0800259# Check that AVB_FOOTER_ARGS_BY_PARTITION is in sync with AVB_PARTITIONS.
260for partition in common.AVB_PARTITIONS:
261 if partition not in AVB_FOOTER_ARGS_BY_PARTITION:
262 raise RuntimeError("Missing {} in AVB_FOOTER_ARGS".format(partition))
263
Daniel Norman78554ea2021-09-14 10:29:38 -0700264# Partitions that can be regenerated after signing using a separate
265# vendor otatools package.
266ALLOWED_VENDOR_PARTITIONS = set(["vendor", "odm"])
267
Tianjiebf0b8a82021-03-03 17:31:04 -0800268
Tianjie4d48d502021-06-11 17:03:43 -0700269def IsApexFile(filename):
270 return filename.endswith(".apex") or filename.endswith(".capex")
271
272
Kelvin Zhangb84d2aa2023-11-06 10:53:41 -0800273def IsOtaPackage(fp):
274 with zipfile.ZipFile(fp) as zfp:
275 if not PAYLOAD_BIN in zfp.namelist():
276 return False
277 with zfp.open(PAYLOAD_BIN, "r") as payload:
278 magic = payload.read(4)
279 return magic == b"CrAU"
280
281
282def IsEntryOtaPackage(input_zip, filename):
283 with input_zip.open(filename, "r") as fp:
284 return IsOtaPackage(fp)
285
286
Tianjie4d48d502021-06-11 17:03:43 -0700287def GetApexFilename(filename):
288 name = os.path.basename(filename)
289 # Replace the suffix for compressed apex
290 if name.endswith(".capex"):
291 return name.replace(".capex", ".apex")
292 return name
293
294
Narayan Kamatha07bf042017-08-14 14:49:21 +0100295def GetApkCerts(certmap):
Kelvin Zhange50bb512022-08-01 15:58:51 -0700296 if OPTIONS.override_apk_keys is not None:
297 for apk in certmap.keys():
298 certmap[apk] = OPTIONS.override_apk_keys
299
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800300 # apply the key remapping to the contents of the file
Tao Baoa3705452019-06-24 15:33:41 -0700301 for apk, cert in certmap.items():
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800302 certmap[apk] = OPTIONS.key_map.get(cert, cert)
303
304 # apply all the -e options, overriding anything in the file
Tao Baoa3705452019-06-24 15:33:41 -0700305 for apk, cert in OPTIONS.extra_apks.items():
Doug Zongkerdecf9952009-12-15 17:27:49 -0800306 if not cert:
307 cert = "PRESIGNED"
Doug Zongkerad88c7c2009-04-14 12:34:27 -0700308 certmap[apk] = OPTIONS.key_map.get(cert, cert)
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800309
Doug Zongkereef39442009-04-02 12:14:19 -0700310 return certmap
311
312
Tao Baoaa7e9932019-03-15 09:37:01 -0700313def GetApexKeys(keys_info, key_map):
314 """Gets APEX payload and container signing keys by applying the mapping rules.
315
Tao Baoe1343992019-03-19 12:24:03 -0700316 Presigned payload / container keys will be set accordingly.
Tao Baoaa7e9932019-03-15 09:37:01 -0700317
318 Args:
319 keys_info: A dict that maps from APEX filenames to a tuple of (payload_key,
Jooyung Han8caba5e2021-10-27 03:58:09 +0900320 container_key, sign_tool).
Tao Baoaa7e9932019-03-15 09:37:01 -0700321 key_map: A dict that overrides the keys, specified via command-line input.
322
323 Returns:
324 A dict that contains the updated APEX key mapping, which should be used for
325 the current signing.
Tao Baof98fa102019-04-24 14:51:25 -0700326
327 Raises:
328 AssertionError: On invalid container / payload key overrides.
Tao Baoaa7e9932019-03-15 09:37:01 -0700329 """
Kelvin Zhange50bb512022-08-01 15:58:51 -0700330 if OPTIONS.override_apex_keys is not None:
331 for apex in keys_info.keys():
332 keys_info[apex] = (OPTIONS.override_apex_keys, keys_info[apex][1], keys_info[apex][2])
333
334 if OPTIONS.override_apk_keys is not None:
335 key = key_map.get(OPTIONS.override_apk_keys, OPTIONS.override_apk_keys)
336 for apex in keys_info.keys():
337 keys_info[apex] = (keys_info[apex][0], key, keys_info[apex][2])
338
Tao Baoaa7e9932019-03-15 09:37:01 -0700339 # Apply all the --extra_apex_payload_key options to override the payload
340 # signing keys in the given keys_info.
341 for apex, key in OPTIONS.extra_apex_payload_keys.items():
Tao Baoe1343992019-03-19 12:24:03 -0700342 if not key:
343 key = 'PRESIGNED'
Tao Bao34223092019-07-11 11:52:52 -0700344 if apex not in keys_info:
345 logger.warning('Failed to find %s in target_files; Ignored', apex)
346 continue
Jooyung Han8caba5e2021-10-27 03:58:09 +0900347 keys_info[apex] = (key, keys_info[apex][1], keys_info[apex][2])
Tao Baoaa7e9932019-03-15 09:37:01 -0700348
349 # Apply the key remapping to container keys.
Jooyung Han8caba5e2021-10-27 03:58:09 +0900350 for apex, (payload_key, container_key, sign_tool) in keys_info.items():
351 keys_info[apex] = (payload_key, key_map.get(container_key, container_key), sign_tool)
Tao Baoaa7e9932019-03-15 09:37:01 -0700352
353 # Apply all the --extra_apks options to override the container keys.
354 for apex, key in OPTIONS.extra_apks.items():
355 # Skip non-APEX containers.
356 if apex not in keys_info:
357 continue
Tao Baoe1343992019-03-19 12:24:03 -0700358 if not key:
359 key = 'PRESIGNED'
Jooyung Han8caba5e2021-10-27 03:58:09 +0900360 keys_info[apex] = (keys_info[apex][0], key_map.get(key, key), keys_info[apex][2])
Tao Baoaa7e9932019-03-15 09:37:01 -0700361
Tao Baof98fa102019-04-24 14:51:25 -0700362 # A PRESIGNED container entails a PRESIGNED payload. Apply this to all the
363 # APEX key pairs. However, a PRESIGNED container with non-PRESIGNED payload
364 # (overridden via commandline) indicates a config error, which should not be
365 # allowed.
Jooyung Han8caba5e2021-10-27 03:58:09 +0900366 for apex, (payload_key, container_key, sign_tool) in keys_info.items():
Tao Baof98fa102019-04-24 14:51:25 -0700367 if container_key != 'PRESIGNED':
368 continue
369 if apex in OPTIONS.extra_apex_payload_keys:
370 payload_override = OPTIONS.extra_apex_payload_keys[apex]
371 assert payload_override == '', \
372 ("Invalid APEX key overrides: {} has PRESIGNED container but "
373 "non-PRESIGNED payload key {}").format(apex, payload_override)
374 if payload_key != 'PRESIGNED':
375 print(
376 "Setting {} payload as PRESIGNED due to PRESIGNED container".format(
377 apex))
Jooyung Han8caba5e2021-10-27 03:58:09 +0900378 keys_info[apex] = ('PRESIGNED', 'PRESIGNED', None)
Tao Baof98fa102019-04-24 14:51:25 -0700379
Tao Baoaa7e9932019-03-15 09:37:01 -0700380 return keys_info
381
382
Tao Bao93c2a012018-06-19 12:19:35 -0700383def GetApkFileInfo(filename, compressed_extension, skipped_prefixes):
Tao Bao11f955c2018-06-19 12:19:35 -0700384 """Returns the APK info based on the given filename.
385
386 Checks if the given filename (with path) looks like an APK file, by taking the
Tao Bao93c2a012018-06-19 12:19:35 -0700387 compressed extension into consideration. If it appears to be an APK file,
388 further checks if the APK file should be skipped when signing, based on the
389 given path prefixes.
Tao Bao11f955c2018-06-19 12:19:35 -0700390
391 Args:
392 filename: Path to the file.
393 compressed_extension: The extension string of compressed APKs (e.g. ".gz"),
394 or None if there's no compressed APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700395 skipped_prefixes: A set/list/tuple of the path prefixes to be skipped.
Tao Bao11f955c2018-06-19 12:19:35 -0700396
397 Returns:
Tao Bao93c2a012018-06-19 12:19:35 -0700398 (is_apk, is_compressed, should_be_skipped): is_apk indicates whether the
399 given filename is an APK file. is_compressed indicates whether the APK file
400 is compressed (only meaningful when is_apk is True). should_be_skipped
401 indicates whether the filename matches any of the given prefixes to be
402 skipped.
Tao Bao11f955c2018-06-19 12:19:35 -0700403
404 Raises:
Tao Bao93c2a012018-06-19 12:19:35 -0700405 AssertionError: On invalid compressed_extension or skipped_prefixes inputs.
Tao Bao11f955c2018-06-19 12:19:35 -0700406 """
407 assert compressed_extension is None or compressed_extension.startswith('.'), \
408 "Invalid compressed_extension arg: '{}'".format(compressed_extension)
409
Tao Bao93c2a012018-06-19 12:19:35 -0700410 # skipped_prefixes should be one of set/list/tuple types. Other types such as
411 # str shouldn't be accepted.
Tao Baobadceb22019-03-15 09:33:43 -0700412 assert isinstance(skipped_prefixes, (set, list, tuple)), \
413 "Invalid skipped_prefixes input type: {}".format(type(skipped_prefixes))
Tao Bao93c2a012018-06-19 12:19:35 -0700414
Tao Bao11f955c2018-06-19 12:19:35 -0700415 compressed_apk_extension = (
416 ".apk" + compressed_extension if compressed_extension else None)
417 is_apk = (filename.endswith(".apk") or
418 (compressed_apk_extension and
419 filename.endswith(compressed_apk_extension)))
420 if not is_apk:
Tao Bao93c2a012018-06-19 12:19:35 -0700421 return (False, False, False)
Tao Bao11f955c2018-06-19 12:19:35 -0700422
423 is_compressed = (compressed_apk_extension and
424 filename.endswith(compressed_apk_extension))
Tao Bao93c2a012018-06-19 12:19:35 -0700425 should_be_skipped = filename.startswith(tuple(skipped_prefixes))
426 return (True, is_compressed, should_be_skipped)
Tao Bao11f955c2018-06-19 12:19:35 -0700427
428
Tao Baoaa7e9932019-03-15 09:37:01 -0700429def CheckApkAndApexKeysAvailable(input_tf_zip, known_keys,
Tao Baoe1343992019-03-19 12:24:03 -0700430 compressed_extension, apex_keys):
Tao Baoaa7e9932019-03-15 09:37:01 -0700431 """Checks that all the APKs and APEXes have keys specified.
Tao Bao11f955c2018-06-19 12:19:35 -0700432
433 Args:
434 input_tf_zip: An open target_files zip file.
Tao Baoaa7e9932019-03-15 09:37:01 -0700435 known_keys: A set of APKs and APEXes that have known signing keys.
Tao Bao11f955c2018-06-19 12:19:35 -0700436 compressed_extension: The extension string of compressed APKs, such as
Tao Baoaa7e9932019-03-15 09:37:01 -0700437 '.gz', or None if there's no compressed APKs.
Tao Baoe1343992019-03-19 12:24:03 -0700438 apex_keys: A dict that contains the key mapping from APEX name to
Jooyung Han8caba5e2021-10-27 03:58:09 +0900439 (payload_key, container_key, sign_tool).
Tao Bao11f955c2018-06-19 12:19:35 -0700440
441 Raises:
Tao Baoaa7e9932019-03-15 09:37:01 -0700442 AssertionError: On finding unknown APKs and APEXes.
Tao Bao11f955c2018-06-19 12:19:35 -0700443 """
Tao Baoaa7e9932019-03-15 09:37:01 -0700444 unknown_files = []
Doug Zongkereb338ef2009-05-20 16:50:49 -0700445 for info in input_tf_zip.infolist():
Tianjie5bd03952021-02-18 23:02:36 -0800446 # Handle APEXes on all partitions
Tianjie4d48d502021-06-11 17:03:43 -0700447 if IsApexFile(info.filename):
448 name = GetApexFilename(info.filename)
Tao Baoaa7e9932019-03-15 09:37:01 -0700449 if name not in known_keys:
450 unknown_files.append(name)
451 continue
452
453 # And APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700454 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
455 info.filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
456 if not is_apk or should_be_skipped:
Tao Bao11f955c2018-06-19 12:19:35 -0700457 continue
Tao Baoaa7e9932019-03-15 09:37:01 -0700458
Tao Bao11f955c2018-06-19 12:19:35 -0700459 name = os.path.basename(info.filename)
460 if is_compressed:
461 name = name[:-len(compressed_extension)]
Tao Baoaa7e9932019-03-15 09:37:01 -0700462 if name not in known_keys:
463 unknown_files.append(name)
Tao Bao11f955c2018-06-19 12:19:35 -0700464
Tao Baoaa7e9932019-03-15 09:37:01 -0700465 assert not unknown_files, \
Tao Bao11f955c2018-06-19 12:19:35 -0700466 ("No key specified for:\n {}\n"
467 "Use '-e <apkname>=' to specify a key (which may be an empty string to "
Tao Baoaa7e9932019-03-15 09:37:01 -0700468 "not sign this apk).".format("\n ".join(unknown_files)))
Doug Zongkereb338ef2009-05-20 16:50:49 -0700469
Tao Baoe1343992019-03-19 12:24:03 -0700470 # For all the APEXes, double check that we won't have an APEX that has only
Tao Baof98fa102019-04-24 14:51:25 -0700471 # one of the payload / container keys set. Note that non-PRESIGNED container
472 # with PRESIGNED payload could be allowed but currently unsupported. It would
473 # require changing SignApex implementation.
Tao Baoe1343992019-03-19 12:24:03 -0700474 if not apex_keys:
475 return
476
477 invalid_apexes = []
478 for info in input_tf_zip.infolist():
Tianjie4d48d502021-06-11 17:03:43 -0700479 if not IsApexFile(info.filename):
Tao Baoe1343992019-03-19 12:24:03 -0700480 continue
481
Tianjie4d48d502021-06-11 17:03:43 -0700482 name = GetApexFilename(info.filename)
483
Jooyung Han8caba5e2021-10-27 03:58:09 +0900484 (payload_key, container_key, _) = apex_keys[name]
Tao Baoe1343992019-03-19 12:24:03 -0700485 if ((payload_key in common.SPECIAL_CERT_STRINGS and
486 container_key not in common.SPECIAL_CERT_STRINGS) or
487 (payload_key not in common.SPECIAL_CERT_STRINGS and
488 container_key in common.SPECIAL_CERT_STRINGS)):
489 invalid_apexes.append(
490 "{}: payload_key {}, container_key {}".format(
491 name, payload_key, container_key))
492
493 assert not invalid_apexes, \
494 "Invalid APEX keys specified:\n {}\n".format(
495 "\n ".join(invalid_apexes))
496
Doug Zongkereb338ef2009-05-20 16:50:49 -0700497
Narayan Kamatha07bf042017-08-14 14:49:21 +0100498def SignApk(data, keyname, pw, platform_api_level, codename_to_api_level_map,
Oleg Aravin8046cb02020-06-02 16:02:38 -0700499 is_compressed, apk_name):
500 unsigned = tempfile.NamedTemporaryFile(suffix='_' + apk_name)
Doug Zongkereef39442009-04-02 12:14:19 -0700501 unsigned.write(data)
502 unsigned.flush()
503
Narayan Kamatha07bf042017-08-14 14:49:21 +0100504 if is_compressed:
505 uncompressed = tempfile.NamedTemporaryFile()
Tao Bao0c28d2d2017-12-24 10:37:38 -0800506 with gzip.open(unsigned.name, "rb") as in_file, \
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400507 open(uncompressed.name, "wb") as out_file:
Narayan Kamatha07bf042017-08-14 14:49:21 +0100508 shutil.copyfileobj(in_file, out_file)
509
510 # Finally, close the "unsigned" file (which is gzip compressed), and then
511 # replace it with the uncompressed version.
512 #
513 # TODO(narayan): All this nastiness can be avoided if python 3.2 is in use,
514 # we could just gzip / gunzip in-memory buffers instead.
515 unsigned.close()
516 unsigned = uncompressed
517
Oleg Aravin8046cb02020-06-02 16:02:38 -0700518 signed = tempfile.NamedTemporaryFile(suffix='_' + apk_name)
Doug Zongkereef39442009-04-02 12:14:19 -0700519
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800520 # For pre-N builds, don't upgrade to SHA-256 JAR signatures based on the APK's
521 # minSdkVersion to avoid increasing incremental OTA update sizes. If an APK
522 # didn't change, we don't want its signature to change due to the switch
523 # from SHA-1 to SHA-256.
524 # By default, APK signer chooses SHA-256 signatures if the APK's minSdkVersion
525 # is 18 or higher. For pre-N builds we disable this mechanism by pretending
526 # that the APK's minSdkVersion is 1.
527 # For N+ builds, we let APK signer rely on the APK's minSdkVersion to
528 # determine whether to use SHA-256.
529 min_api_level = None
530 if platform_api_level > 23:
531 # Let APK signer choose whether to use SHA-1 or SHA-256, based on the APK's
532 # minSdkVersion attribute
533 min_api_level = None
534 else:
535 # Force APK signer to use SHA-1
536 min_api_level = 1
537
538 common.SignFile(unsigned.name, signed.name, keyname, pw,
Tao Bao0c28d2d2017-12-24 10:37:38 -0800539 min_api_level=min_api_level,
540 codename_to_api_level_map=codename_to_api_level_map)
Doug Zongkereef39442009-04-02 12:14:19 -0700541
Tao Bao0c28d2d2017-12-24 10:37:38 -0800542 data = None
Narayan Kamatha07bf042017-08-14 14:49:21 +0100543 if is_compressed:
544 # Recompress the file after it has been signed.
545 compressed = tempfile.NamedTemporaryFile()
Tao Bao0c28d2d2017-12-24 10:37:38 -0800546 with open(signed.name, "rb") as in_file, \
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400547 gzip.open(compressed.name, "wb") as out_file:
Narayan Kamatha07bf042017-08-14 14:49:21 +0100548 shutil.copyfileobj(in_file, out_file)
549
550 data = compressed.read()
551 compressed.close()
552 else:
553 data = signed.read()
554
Doug Zongkereef39442009-04-02 12:14:19 -0700555 unsigned.close()
556 signed.close()
557
558 return data
559
Tianjie5bd03952021-02-18 23:02:36 -0800560
Kelvin Zhangb84d2aa2023-11-06 10:53:41 -0800561
Kelvin Zhang119f2792021-02-10 12:45:24 -0500562def IsBuildPropFile(filename):
563 return filename in (
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400564 "SYSTEM/etc/prop.default",
565 "BOOT/RAMDISK/prop.default",
566 "RECOVERY/RAMDISK/prop.default",
Kelvin Zhang119f2792021-02-10 12:45:24 -0500567
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400568 "VENDOR_BOOT/RAMDISK/default.prop",
569 "VENDOR_BOOT/RAMDISK/prop.default",
Kelvin Zhang119f2792021-02-10 12:45:24 -0500570
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400571 # ROOT/default.prop is a legacy path, but may still exist for upgrading
572 # devices that don't support `property_overrides_split_enabled`.
573 "ROOT/default.prop",
Kelvin Zhang119f2792021-02-10 12:45:24 -0500574
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400575 # RECOVERY/RAMDISK/default.prop is a legacy path, but will always exist
576 # as a symlink in the current code. So it's a no-op here. Keeping the
577 # path here for clarity.
Kelvin Zhang30669e62023-01-10 21:02:02 -0800578 # Some build props might be stored under path
Hongguang Chen1a732332023-01-29 10:51:19 -0800579 # VENDOR_BOOT/RAMDISK_FRAGMENTS/recovery/RAMDISK/default.prop, and
580 # default.prop can be a symbolic link to prop.default, so overwrite all
581 # files that ends with build.prop, default.prop or prop.default
Kelvin Zhang30669e62023-01-10 21:02:02 -0800582 "RECOVERY/RAMDISK/default.prop") or \
583 filename.endswith("build.prop") or \
Hongguang Chen1a732332023-01-29 10:51:19 -0800584 filename.endswith("/default.prop") or \
585 filename.endswith("/prop.default")
Doug Zongkereef39442009-04-02 12:14:19 -0700586
Tianjie5bd03952021-02-18 23:02:36 -0800587
Kelvin Zhangb84d2aa2023-11-06 10:53:41 -0800588def ProcessTargetFiles(input_tf_zip: zipfile.ZipFile, output_tf_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -0700589 apk_keys, apex_keys, key_passwords,
590 platform_api_level, codename_to_api_level_map,
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +0000591 compressed_extension):
Tao Bao93c2a012018-06-19 12:19:35 -0700592 # maxsize measures the maximum filename length, including the ones to be
593 # skipped.
Bowgo Tsai8d4b7242022-01-04 15:15:35 +0800594 try:
595 maxsize = max(
596 [len(os.path.basename(i.filename)) for i in input_tf_zip.infolist()
597 if GetApkFileInfo(i.filename, compressed_extension, [])[0]])
598 except ValueError:
599 # Sets this to zero for targets without APK files, e.g., gki_arm64.
600 maxsize = 0
601
Tao Baoa80ed222016-06-16 14:41:24 -0700602 system_root_image = misc_info.get("system_root_image") == "true"
Doug Zongker412c02f2014-02-13 10:58:24 -0800603
Doug Zongkereef39442009-04-02 12:14:19 -0700604 for info in input_tf_zip.infolist():
Tao Bao11f955c2018-06-19 12:19:35 -0700605 filename = info.filename
606 if filename.startswith("IMAGES/"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700607 continue
Doug Zongker3c84f562014-07-31 11:06:30 -0700608
Tao Bao04808502019-07-25 23:11:41 -0700609 # Skip OTA-specific images (e.g. split super images), which will be
610 # re-generated during signing.
Tao Bao33bf2682019-01-11 12:37:35 -0800611 if filename.startswith("OTA/") and filename.endswith(".img"):
612 continue
613
Tao Bao11f955c2018-06-19 12:19:35 -0700614 data = input_tf_zip.read(filename)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700615 out_info = copy.copy(info)
Tao Bao93c2a012018-06-19 12:19:35 -0700616 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
617 filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
618
619 if is_apk and should_be_skipped:
620 # Copy skipped APKs verbatim.
621 print(
622 "NOT signing: %s\n"
623 " (skipped due to matching prefix)" % (filename,))
624 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker412c02f2014-02-13 10:58:24 -0800625
Tao Baof2cffbd2015-07-22 12:33:18 -0700626 # Sign APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700627 elif is_apk:
Tao Bao11f955c2018-06-19 12:19:35 -0700628 name = os.path.basename(filename)
Narayan Kamatha07bf042017-08-14 14:49:21 +0100629 if is_compressed:
630 name = name[:-len(compressed_extension)]
631
Tao Baoaa7e9932019-03-15 09:37:01 -0700632 key = apk_keys[name]
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800633 if key not in common.SPECIAL_CERT_STRINGS:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800634 print(" signing: %-*s (%s)" % (maxsize, name, key))
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800635 signed_data = SignApk(data, key, key_passwords[key], platform_api_level,
Oleg Aravin8046cb02020-06-02 16:02:38 -0700636 codename_to_api_level_map, is_compressed, name)
Tao Bao2ed665a2015-04-01 11:21:55 -0700637 common.ZipWriteStr(output_tf_zip, out_info, signed_data)
Doug Zongkereef39442009-04-02 12:14:19 -0700638 else:
639 # an APK we're not supposed to sign.
Tao Bao93c2a012018-06-19 12:19:35 -0700640 print(
641 "NOT signing: %s\n"
642 " (skipped due to special cert string)" % (name,))
Tao Bao2ed665a2015-04-01 11:21:55 -0700643 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoa80ed222016-06-16 14:41:24 -0700644
Tianjie5bd03952021-02-18 23:02:36 -0800645 # Sign bundled APEX files on all partitions
Tianjie4d48d502021-06-11 17:03:43 -0700646 elif IsApexFile(filename):
647 name = GetApexFilename(filename)
648
Jooyung Han8caba5e2021-10-27 03:58:09 +0900649 payload_key, container_key, sign_tool = apex_keys[name]
Tao Baoaa7e9932019-03-15 09:37:01 -0700650
Tao Baoe1343992019-03-19 12:24:03 -0700651 # We've asserted not having a case with only one of them PRESIGNED.
652 if (payload_key not in common.SPECIAL_CERT_STRINGS and
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400653 container_key not in common.SPECIAL_CERT_STRINGS):
Tao Baoe1343992019-03-19 12:24:03 -0700654 print(" signing: %-*s container (%s)" % (
655 maxsize, name, container_key))
656 print(" : %-*s payload (%s)" % (
657 maxsize, name, payload_key))
Tao Baoaa7e9932019-03-15 09:37:01 -0700658
Tao Baoe7354ba2019-05-09 16:54:15 -0700659 signed_apex = apex_utils.SignApex(
Tao Bao1ac886e2019-06-26 11:58:22 -0700660 misc_info['avb_avbtool'],
Tao Baoe1343992019-03-19 12:24:03 -0700661 data,
662 payload_key,
663 container_key,
Oleh Cherpake555ab12020-10-05 17:04:59 +0300664 key_passwords,
Tianjie Xu88a759d2020-01-23 10:47:54 -0800665 apk_keys,
Tao Baoe1343992019-03-19 12:24:03 -0700666 codename_to_api_level_map,
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400667 no_hashtree=None, # Let apex_util determine if hash tree is needed
Jooyung Han8caba5e2021-10-27 03:58:09 +0900668 signing_args=OPTIONS.avb_extra_args.get('apex'),
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +0000669 sign_tool=sign_tool)
Tao Baoe1343992019-03-19 12:24:03 -0700670 common.ZipWrite(output_tf_zip, signed_apex, filename)
Tao Baoaa7e9932019-03-15 09:37:01 -0700671
Tao Baoe1343992019-03-19 12:24:03 -0700672 else:
673 print(
674 "NOT signing: %s\n"
675 " (skipped due to special cert string)" % (name,))
676 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoaa7e9932019-03-15 09:37:01 -0700677
Kelvin Zhangb84d2aa2023-11-06 10:53:41 -0800678 elif filename.endswith(".zip") and IsEntryOtaPackage(input_tf_zip, filename):
679 logger.info("Re-signing OTA package {}".format(filename))
680 with tempfile.NamedTemporaryFile() as input_ota, tempfile.NamedTemporaryFile() as output_ota:
681 with input_tf_zip.open(filename, "r") as in_fp:
682 shutil.copyfileobj(in_fp, input_ota)
683 input_ota.flush()
684 SignOtaPackage(input_ota.name, output_ota.name)
685 common.ZipWrite(output_tf_zip, output_ota.name, filename,
686 compress_type=zipfile.ZIP_STORED)
Tao Baoa80ed222016-06-16 14:41:24 -0700687 # System properties.
Kelvin Zhang119f2792021-02-10 12:45:24 -0500688 elif IsBuildPropFile(filename):
Tao Bao11f955c2018-06-19 12:19:35 -0700689 print("Rewriting %s:" % (filename,))
Hung-ying Tyan7eb6a922017-05-01 21:56:26 +0800690 if stat.S_ISLNK(info.external_attr >> 16):
691 new_data = data
692 else:
Tao Baoa3705452019-06-24 15:33:41 -0700693 new_data = RewriteProps(data.decode())
Tao Bao2ed665a2015-04-01 11:21:55 -0700694 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700695
Tao Bao66472632017-12-04 17:16:36 -0800696 # Replace the certs in *mac_permissions.xml (there could be multiple, such
Inseob Kime7b222a2021-12-21 15:57:03 +0900697 # as {system,vendor}/etc/selinux/{plat,vendor}_mac_permissions.xml).
Tao Bao11f955c2018-06-19 12:19:35 -0700698 elif filename.endswith("mac_permissions.xml"):
699 print("Rewriting %s with new keys." % (filename,))
Tao Baoa3705452019-06-24 15:33:41 -0700700 new_data = ReplaceCerts(data.decode())
Tao Bao2ed665a2015-04-01 11:21:55 -0700701 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700702
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700703 # Ask add_img_to_target_files to rebuild the recovery patch if needed.
Tao Bao11f955c2018-06-19 12:19:35 -0700704 elif filename in ("SYSTEM/recovery-from-boot.p",
Robin Leeda427de2020-01-03 19:16:32 +0100705 "VENDOR/recovery-from-boot.p",
706
Tao Bao11f955c2018-06-19 12:19:35 -0700707 "SYSTEM/etc/recovery.img",
Robin Leeda427de2020-01-03 19:16:32 +0100708 "VENDOR/etc/recovery.img",
709
710 "SYSTEM/bin/install-recovery.sh",
711 "VENDOR/bin/install-recovery.sh"):
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700712 OPTIONS.rebuild_recovery = True
Tao Baoa80ed222016-06-16 14:41:24 -0700713
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700714 # Don't copy OTA certs if we're replacing them.
Tianjie Xu2df23d72019-10-15 18:06:25 -0700715 # Replacement of update-payload-key.pub.pem was removed in b/116660991.
Kelvin Zhang9f781ff2021-02-11 19:10:44 -0500716 elif OPTIONS.replace_ota_keys and filename.endswith("/otacerts.zip"):
Doug Zongker412c02f2014-02-13 10:58:24 -0800717 pass
Tao Baoa80ed222016-06-16 14:41:24 -0700718
Tao Bao46a59992017-06-05 11:55:16 -0700719 # Skip META/misc_info.txt since we will write back the new values later.
Tao Bao11f955c2018-06-19 12:19:35 -0700720 elif filename == "META/misc_info.txt":
Geremy Condraf19b3652014-07-29 17:54:54 -0700721 pass
Tao Bao8adcfd12016-06-17 17:01:22 -0700722
Bowgo Tsai2fe786a2020-02-21 17:48:18 +0800723 elif (OPTIONS.remove_avb_public_keys and
724 (filename.startswith("BOOT/RAMDISK/avb/") or
725 filename.startswith("BOOT/RAMDISK/first_stage_ramdisk/avb/"))):
Kelvin Zhang0876c412020-06-23 15:06:58 -0400726 matched_removal = False
727 for key_to_remove in OPTIONS.remove_avb_public_keys:
728 if filename.endswith(key_to_remove):
729 matched_removal = True
730 print("Removing AVB public key from ramdisk: %s" % filename)
731 break
732 if not matched_removal:
733 # Copy it verbatim if we don't want to remove it.
734 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoa80ed222016-06-16 14:41:24 -0700735
Tianjiebbde59f2021-05-03 21:18:56 -0700736 # Skip the vbmeta digest as we will recalculate it.
737 elif filename == "META/vbmeta_digest.txt":
738 pass
739
Tianjie Xu4f099002016-08-11 18:04:27 -0700740 # Skip the care_map as we will regenerate the system/vendor images.
Kelvin Zhang0876c412020-06-23 15:06:58 -0400741 elif filename in ["META/care_map.pb", "META/care_map.txt"]:
Tianjie Xu4f099002016-08-11 18:04:27 -0700742 pass
743
Kelvin Zhang5f0fcee2021-01-19 15:30:46 -0500744 # Skip apex_info.pb because we sign/modify apexes
745 elif filename == "META/apex_info.pb":
746 pass
747
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800748 # Updates system_other.avbpubkey in /product/etc/.
749 elif filename in (
750 "PRODUCT/etc/security/avb/system_other.avbpubkey",
Bowgo Tsai2a781692021-10-13 17:39:33 +0800751 "SYSTEM/product/etc/security/avb/system_other.avbpubkey"):
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800752 # Only update system_other's public key, if the corresponding signing
753 # key is specified via --avb_system_other_key.
754 signing_key = OPTIONS.avb_keys.get("system_other")
755 if signing_key:
Tao Bao1ac886e2019-06-26 11:58:22 -0700756 public_key = common.ExtractAvbPublicKey(
757 misc_info['avb_avbtool'], signing_key)
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800758 print(" Rewriting AVB public key of system_other in /product")
759 common.ZipWrite(output_tf_zip, public_key, filename)
760
Andrew Scullbbc930b2022-02-17 22:34:27 +0000761 # Updates pvmfw embedded public key with the virt APEX payload key.
762 elif filename == "PREBUILT_IMAGES/pvmfw.img":
763 # Find the name of the virt APEX in the target files.
764 namelist = input_tf_zip.namelist()
765 apex_gen = (GetApexFilename(f) for f in namelist if IsApexFile(f))
766 virt_apex_re = re.compile("^com\.([^\.]+\.)?android\.virt\.apex$")
767 virt_apex = next((a for a in apex_gen if virt_apex_re.match(a)), None)
768 if not virt_apex:
769 print("Removing %s from ramdisk: virt APEX not found" % filename)
770 else:
771 print("Replacing %s embedded key with %s key" % (filename, virt_apex))
772 # Get the current and new embedded keys.
773 payload_key, container_key, sign_tool = apex_keys[virt_apex]
774 new_pubkey_path = common.ExtractAvbPublicKey(
775 misc_info['avb_avbtool'], payload_key)
776 with open(new_pubkey_path, 'rb') as f:
777 new_pubkey = f.read()
778 pubkey_info = copy.copy(
779 input_tf_zip.getinfo("PREBUILT_IMAGES/pvmfw_embedded.avbpubkey"))
780 old_pubkey = input_tf_zip.read(pubkey_info.filename)
781 # Validate the keys and image.
782 if len(old_pubkey) != len(new_pubkey):
783 raise common.ExternalError("pvmfw embedded public key size mismatch")
784 pos = data.find(old_pubkey)
785 if pos == -1:
786 raise common.ExternalError("pvmfw embedded public key not found")
787 # Replace the key and copy new files.
788 new_data = data[:pos] + new_pubkey + data[pos+len(old_pubkey):]
789 common.ZipWriteStr(output_tf_zip, out_info, new_data)
790 common.ZipWriteStr(output_tf_zip, pubkey_info, new_pubkey)
791 elif filename == "PREBUILT_IMAGES/pvmfw_embedded.avbpubkey":
792 pass
793
Bowgo Tsai78369eb2019-04-23 12:28:44 +0800794 # Should NOT sign boot-debug.img.
795 elif filename in (
796 "BOOT/RAMDISK/force_debuggable",
Bowgo Tsai2a781692021-10-13 17:39:33 +0800797 "BOOT/RAMDISK/first_stage_ramdisk/force_debuggable"):
Bowgo Tsai78369eb2019-04-23 12:28:44 +0800798 raise common.ExternalError("debuggable boot.img cannot be signed")
799
Bowgo Tsai2a781692021-10-13 17:39:33 +0800800 # Should NOT sign userdebug sepolicy file.
801 elif filename in (
802 "SYSTEM_EXT/etc/selinux/userdebug_plat_sepolicy.cil",
803 "SYSTEM/system_ext/etc/selinux/userdebug_plat_sepolicy.cil"):
804 if not OPTIONS.allow_gsi_debug_sepolicy:
805 raise common.ExternalError("debug sepolicy shouldn't be included")
806 else:
807 # Copy it verbatim if we allow the file to exist.
808 common.ZipWriteStr(output_tf_zip, out_info, data)
809
Tao Baoa80ed222016-06-16 14:41:24 -0700810 # A non-APK file; copy it verbatim.
Doug Zongkereef39442009-04-02 12:14:19 -0700811 else:
Tao Bao2ed665a2015-04-01 11:21:55 -0700812 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700813
Doug Zongker412c02f2014-02-13 10:58:24 -0800814 if OPTIONS.replace_ota_keys:
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700815 ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info)
Doug Zongker412c02f2014-02-13 10:58:24 -0800816
Tao Bao639118f2017-06-19 15:48:02 -0700817 # Replace the AVB signing keys, if any.
818 ReplaceAvbSigningKeys(misc_info)
819
Tao Bao19b02fe2019-10-09 00:04:28 -0700820 # Rewrite the props in AVB signing args.
821 if misc_info.get('avb_enable') == 'true':
822 RewriteAvbProps(misc_info)
823
Bowgo Tsai27c39b02021-03-12 21:40:32 +0800824 # Replace the GKI signing key for boot.img, if any.
825 ReplaceGkiSigningKey(misc_info)
826
Tao Bao46a59992017-06-05 11:55:16 -0700827 # Write back misc_info with the latest values.
828 ReplaceMiscInfoTxt(input_tf_zip, output_tf_zip, misc_info)
829
Doug Zongker8e931bf2009-04-06 15:21:45 -0700830
Robert Craig817c5742013-04-19 10:59:22 -0400831def ReplaceCerts(data):
Tao Bao66472632017-12-04 17:16:36 -0800832 """Replaces all the occurences of X.509 certs with the new ones.
Robert Craig817c5742013-04-19 10:59:22 -0400833
Tao Bao66472632017-12-04 17:16:36 -0800834 The mapping info is read from OPTIONS.key_map. Non-existent certificate will
835 be skipped. After the replacement, it additionally checks for duplicate
836 entries, which would otherwise fail the policy loading code in
837 frameworks/base/services/core/java/com/android/server/pm/SELinuxMMAC.java.
838
839 Args:
840 data: Input string that contains a set of X.509 certs.
841
842 Returns:
843 A string after the replacement.
844
845 Raises:
846 AssertionError: On finding duplicate entries.
847 """
Tao Baoa3705452019-06-24 15:33:41 -0700848 for old, new in OPTIONS.key_map.items():
Tao Bao66472632017-12-04 17:16:36 -0800849 if OPTIONS.verbose:
850 print(" Replacing %s.x509.pem with %s.x509.pem" % (old, new))
851
852 try:
853 with open(old + ".x509.pem") as old_fp:
854 old_cert16 = base64.b16encode(
Tao Baoa3705452019-06-24 15:33:41 -0700855 common.ParseCertificate(old_fp.read())).decode().lower()
Tao Bao66472632017-12-04 17:16:36 -0800856 with open(new + ".x509.pem") as new_fp:
857 new_cert16 = base64.b16encode(
Tao Baoa3705452019-06-24 15:33:41 -0700858 common.ParseCertificate(new_fp.read())).decode().lower()
Tao Bao66472632017-12-04 17:16:36 -0800859 except IOError as e:
860 if OPTIONS.verbose or e.errno != errno.ENOENT:
861 print(" Error accessing %s: %s.\nSkip replacing %s.x509.pem with "
862 "%s.x509.pem." % (e.filename, e.strerror, old, new))
863 continue
864
865 # Only match entire certs.
866 pattern = "\\b" + old_cert16 + "\\b"
867 (data, num) = re.subn(pattern, new_cert16, data, flags=re.IGNORECASE)
868
869 if OPTIONS.verbose:
870 print(" Replaced %d occurence(s) of %s.x509.pem with %s.x509.pem" % (
871 num, old, new))
872
873 # Verify that there're no duplicate entries after the replacement. Note that
874 # it's only checking entries with global seinfo at the moment (i.e. ignoring
875 # the ones with inner packages). (Bug: 69479366)
876 root = ElementTree.fromstring(data)
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400877 signatures = [signer.attrib['signature']
878 for signer in root.findall('signer')]
Tao Bao66472632017-12-04 17:16:36 -0800879 assert len(signatures) == len(set(signatures)), \
880 "Found duplicate entries after cert replacement: {}".format(data)
Robert Craig817c5742013-04-19 10:59:22 -0400881
882 return data
883
884
Doug Zongkerc09abc82010-01-11 13:09:15 -0800885def EditTags(tags):
Tao Baoa7054ee2017-12-08 14:42:16 -0800886 """Applies the edits to the tag string as specified in OPTIONS.tag_changes.
887
888 Args:
889 tags: The input string that contains comma-separated tags.
890
891 Returns:
892 The updated tags (comma-separated and sorted).
893 """
Doug Zongkerc09abc82010-01-11 13:09:15 -0800894 tags = set(tags.split(","))
895 for ch in OPTIONS.tag_changes:
896 if ch[0] == "-":
897 tags.discard(ch[1:])
898 elif ch[0] == "+":
899 tags.add(ch[1:])
900 return ",".join(sorted(tags))
901
902
Tao Baoa7054ee2017-12-08 14:42:16 -0800903def RewriteProps(data):
904 """Rewrites the system properties in the given string.
905
906 Each property is expected in 'key=value' format. The properties that contain
907 build tags (i.e. test-keys, dev-keys) will be updated accordingly by calling
908 EditTags().
909
910 Args:
911 data: Input string, separated by newlines.
912
913 Returns:
914 The string with modified properties.
915 """
Doug Zongker17aa9442009-04-17 10:15:58 -0700916 output = []
917 for line in data.split("\n"):
918 line = line.strip()
919 original_line = line
Michael Rungedc2661a2014-06-03 14:43:11 -0700920 if line and line[0] != '#' and "=" in line:
Doug Zongker17aa9442009-04-17 10:15:58 -0700921 key, value = line.split("=", 1)
Magnus Strandh234f4b42019-05-01 23:09:30 +0200922 if (key.startswith("ro.") and
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400923 key.endswith((".build.fingerprint", ".build.thumbprint"))):
Doug Zongkerc09abc82010-01-11 13:09:15 -0800924 pieces = value.split("/")
925 pieces[-1] = EditTags(pieces[-1])
926 value = "/".join(pieces)
Tao Baocb7ff772015-09-11 15:27:56 -0700927 elif key == "ro.bootimage.build.fingerprint":
928 pieces = value.split("/")
929 pieces[-1] = EditTags(pieces[-1])
930 value = "/".join(pieces)
Doug Zongker17aa9442009-04-17 10:15:58 -0700931 elif key == "ro.build.description":
jiajia tange5ddfcd2022-06-21 10:36:12 +0800932 pieces = value.split()
Stefen Wakefield4260fc12021-03-23 04:58:22 -0500933 assert pieces[-1].endswith("-keys")
Doug Zongkerc09abc82010-01-11 13:09:15 -0800934 pieces[-1] = EditTags(pieces[-1])
935 value = " ".join(pieces)
Magnus Strandh234f4b42019-05-01 23:09:30 +0200936 elif key.startswith("ro.") and key.endswith(".build.tags"):
Doug Zongkerc09abc82010-01-11 13:09:15 -0800937 value = EditTags(value)
Doug Zongkera8608a72013-07-23 11:51:04 -0700938 elif key == "ro.build.display.id":
939 # change, eg, "JWR66N dev-keys" to "JWR66N"
940 value = value.split()
Michael Rungedc2661a2014-06-03 14:43:11 -0700941 if len(value) > 1 and value[-1].endswith("-keys"):
Andrew Boie73d5abb2013-12-11 12:42:03 -0800942 value.pop()
943 value = " ".join(value)
Doug Zongkerc09abc82010-01-11 13:09:15 -0800944 line = key + "=" + value
Doug Zongker17aa9442009-04-17 10:15:58 -0700945 if line != original_line:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800946 print(" replace: ", original_line)
947 print(" with: ", line)
Doug Zongker17aa9442009-04-17 10:15:58 -0700948 output.append(line)
949 return "\n".join(output) + "\n"
950
951
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700952def WriteOtacerts(output_zip, filename, keys):
953 """Constructs a zipfile from given keys; and writes it to output_zip.
954
955 Args:
956 output_zip: The output target_files zip.
957 filename: The archive name in the output zip.
958 keys: A list of public keys to use during OTA package verification.
959 """
Tao Baobb733882019-07-24 23:31:19 -0700960 temp_file = io.BytesIO()
Kelvin Zhang928c2342020-09-22 16:15:57 -0400961 certs_zip = zipfile.ZipFile(temp_file, "w", allowZip64=True)
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700962 for k in keys:
963 common.ZipWrite(certs_zip, k)
Kelvin Zhangf92f7f02023-04-14 21:32:54 +0000964 common.ZipClose(certs_zip)
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700965 common.ZipWriteStr(output_zip, filename, temp_file.getvalue())
966
967
Doug Zongker831840e2011-09-22 10:28:04 -0700968def ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info):
Doug Zongker8e931bf2009-04-06 15:21:45 -0700969 try:
970 keylist = input_tf_zip.read("META/otakeys.txt").split()
971 except KeyError:
T.R. Fullharta28acc62013-03-18 10:31:26 -0700972 raise common.ExternalError("can't read META/otakeys.txt from input")
Doug Zongker8e931bf2009-04-06 15:21:45 -0700973
Jacky Liubeb0b692021-12-29 16:29:05 +0800974 extra_ota_keys_info = misc_info.get("extra_ota_keys")
975 if extra_ota_keys_info:
976 extra_ota_keys = [OPTIONS.key_map.get(k, k) + ".x509.pem"
977 for k in extra_ota_keys_info.split()]
978 print("extra ota key(s): " + ", ".join(extra_ota_keys))
979 else:
980 extra_ota_keys = []
981 for k in extra_ota_keys:
982 if not os.path.isfile(k):
983 raise common.ExternalError(k + " does not exist or is not a file")
984
985 extra_recovery_keys_info = misc_info.get("extra_recovery_keys")
986 if extra_recovery_keys_info:
Doug Zongkere121d6a2011-02-01 14:13:52 -0800987 extra_recovery_keys = [OPTIONS.key_map.get(k, k) + ".x509.pem"
Jacky Liubeb0b692021-12-29 16:29:05 +0800988 for k in extra_recovery_keys_info.split()]
989 print("extra recovery-only key(s): " + ", ".join(extra_recovery_keys))
Doug Zongkere121d6a2011-02-01 14:13:52 -0800990 else:
991 extra_recovery_keys = []
Jacky Liubeb0b692021-12-29 16:29:05 +0800992 for k in extra_recovery_keys:
993 if not os.path.isfile(k):
994 raise common.ExternalError(k + " does not exist or is not a file")
Doug Zongkere121d6a2011-02-01 14:13:52 -0800995
Doug Zongker8e931bf2009-04-06 15:21:45 -0700996 mapped_keys = []
997 for k in keylist:
998 m = re.match(r"^(.*)\.x509\.pem$", k)
999 if not m:
Doug Zongker412c02f2014-02-13 10:58:24 -08001000 raise common.ExternalError(
1001 "can't parse \"%s\" from META/otakeys.txt" % (k,))
Doug Zongker8e931bf2009-04-06 15:21:45 -07001002 k = m.group(1)
1003 mapped_keys.append(OPTIONS.key_map.get(k, k) + ".x509.pem")
1004
Doug Zongkere05628c2009-08-20 17:38:42 -07001005 if mapped_keys:
Tao Bao0c28d2d2017-12-24 10:37:38 -08001006 print("using:\n ", "\n ".join(mapped_keys))
1007 print("for OTA package verification")
Doug Zongkere05628c2009-08-20 17:38:42 -07001008 else:
Doug Zongker831840e2011-09-22 10:28:04 -07001009 devkey = misc_info.get("default_system_dev_certificate",
Dan Willemsen0ab1be62019-04-09 21:35:37 -07001010 "build/make/target/product/security/testkey")
Tao Baof718f902017-11-09 10:10:10 -08001011 mapped_devkey = OPTIONS.key_map.get(devkey, devkey)
1012 if mapped_devkey != devkey:
1013 misc_info["default_system_dev_certificate"] = mapped_devkey
1014 mapped_keys.append(mapped_devkey + ".x509.pem")
Tao Baoa80ed222016-06-16 14:41:24 -07001015 print("META/otakeys.txt has no keys; using %s for OTA package"
1016 " verification." % (mapped_keys[0],))
Jacky Liubeb0b692021-12-29 16:29:05 +08001017 for k in mapped_keys:
1018 if not os.path.isfile(k):
1019 raise common.ExternalError(k + " does not exist or is not a file")
Doug Zongker8e931bf2009-04-06 15:21:45 -07001020
Kelvin Zhang9f781ff2021-02-11 19:10:44 -05001021 otacerts = [info
1022 for info in input_tf_zip.infolist()
1023 if info.filename.endswith("/otacerts.zip")]
1024 for info in otacerts:
Jacky Liubeb0b692021-12-29 16:29:05 +08001025 if info.filename.startswith(("BOOT/", "RECOVERY/", "VENDOR_BOOT/")):
1026 extra_keys = extra_recovery_keys
1027 else:
1028 extra_keys = extra_ota_keys
1029 print("Rewriting OTA key:", info.filename, mapped_keys + extra_keys)
1030 WriteOtacerts(output_tf_zip, info.filename, mapped_keys + extra_keys)
Doug Zongkereef39442009-04-02 12:14:19 -07001031
Tao Baoa80ed222016-06-16 14:41:24 -07001032
Tao Bao46a59992017-06-05 11:55:16 -07001033def ReplaceMiscInfoTxt(input_zip, output_zip, misc_info):
1034 """Replaces META/misc_info.txt.
1035
1036 Only writes back the ones in the original META/misc_info.txt. Because the
1037 current in-memory dict contains additional items computed at runtime.
1038 """
1039 misc_info_old = common.LoadDictionaryFromLines(
Tao Baoa3705452019-06-24 15:33:41 -07001040 input_zip.read('META/misc_info.txt').decode().split('\n'))
Tao Bao46a59992017-06-05 11:55:16 -07001041 items = []
1042 for key in sorted(misc_info):
1043 if key in misc_info_old:
1044 items.append('%s=%s' % (key, misc_info[key]))
1045 common.ZipWriteStr(output_zip, "META/misc_info.txt", '\n'.join(items))
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001046
Tao Bao8adcfd12016-06-17 17:01:22 -07001047
Tao Bao639118f2017-06-19 15:48:02 -07001048def ReplaceAvbSigningKeys(misc_info):
1049 """Replaces the AVB signing keys."""
1050
Tao Bao639118f2017-06-19 15:48:02 -07001051 def ReplaceAvbPartitionSigningKey(partition):
1052 key = OPTIONS.avb_keys.get(partition)
1053 if not key:
1054 return
1055
1056 algorithm = OPTIONS.avb_algorithms.get(partition)
1057 assert algorithm, 'Missing AVB signing algorithm for %s' % (partition,)
1058
Tao Bao0c28d2d2017-12-24 10:37:38 -08001059 print('Replacing AVB signing key for %s with "%s" (%s)' % (
1060 partition, key, algorithm))
Tao Bao639118f2017-06-19 15:48:02 -07001061 misc_info['avb_' + partition + '_algorithm'] = algorithm
1062 misc_info['avb_' + partition + '_key_path'] = key
1063
1064 extra_args = OPTIONS.avb_extra_args.get(partition)
1065 if extra_args:
Tao Bao0c28d2d2017-12-24 10:37:38 -08001066 print('Setting extra AVB signing args for %s to "%s"' % (
1067 partition, extra_args))
Kelvin Zhang0876c412020-06-23 15:06:58 -04001068 args_key = AVB_FOOTER_ARGS_BY_PARTITION.get(
1069 partition,
1070 # custom partition
1071 "avb_{}_add_hashtree_footer_args".format(partition))
Tao Bao639118f2017-06-19 15:48:02 -07001072 misc_info[args_key] = (misc_info.get(args_key, '') + ' ' + extra_args)
1073
1074 for partition in AVB_FOOTER_ARGS_BY_PARTITION:
1075 ReplaceAvbPartitionSigningKey(partition)
1076
Hongguang Chenf23364d2020-04-27 18:36:36 -07001077 for custom_partition in misc_info.get(
Kelvin Zhang7cab7502021-08-02 19:58:14 -04001078 "avb_custom_images_partition_list", "").strip().split():
Hongguang Chenf23364d2020-04-27 18:36:36 -07001079 ReplaceAvbPartitionSigningKey(custom_partition)
1080
Tao Bao639118f2017-06-19 15:48:02 -07001081
Tao Bao19b02fe2019-10-09 00:04:28 -07001082def RewriteAvbProps(misc_info):
1083 """Rewrites the props in AVB signing args."""
1084 for partition, args_key in AVB_FOOTER_ARGS_BY_PARTITION.items():
1085 args = misc_info.get(args_key)
1086 if not args:
1087 continue
1088
1089 tokens = []
1090 changed = False
jiajia tange5ddfcd2022-06-21 10:36:12 +08001091 for token in args.split():
Tao Bao19b02fe2019-10-09 00:04:28 -07001092 fingerprint_key = 'com.android.build.{}.fingerprint'.format(partition)
1093 if not token.startswith(fingerprint_key):
1094 tokens.append(token)
1095 continue
1096 prefix, tag = token.rsplit('/', 1)
1097 tokens.append('{}/{}'.format(prefix, EditTags(tag)))
1098 changed = True
1099
1100 if changed:
1101 result = ' '.join(tokens)
1102 print('Rewriting AVB prop for {}:\n'.format(partition))
1103 print(' replace: {}'.format(args))
1104 print(' with: {}'.format(result))
1105 misc_info[args_key] = result
1106
1107
Bowgo Tsai27c39b02021-03-12 21:40:32 +08001108def ReplaceGkiSigningKey(misc_info):
1109 """Replaces the GKI signing key."""
1110
1111 key = OPTIONS.gki_signing_key
1112 if not key:
1113 return
1114
1115 algorithm = OPTIONS.gki_signing_algorithm
1116 if not algorithm:
1117 raise ValueError("Missing --gki_signing_algorithm")
1118
1119 print('Replacing GKI signing key with "%s" (%s)' % (key, algorithm))
1120 misc_info["gki_signing_algorithm"] = algorithm
1121 misc_info["gki_signing_key_path"] = key
1122
1123 extra_args = OPTIONS.gki_signing_extra_args
1124 if extra_args:
Bowgo Tsaibcae74d2021-05-10 17:35:37 +08001125 print('Setting GKI signing args: "%s"' % (extra_args))
1126 misc_info["gki_signing_signature_args"] = extra_args
Bowgo Tsai27c39b02021-03-12 21:40:32 +08001127
1128
Doug Zongker831840e2011-09-22 10:28:04 -07001129def BuildKeyMap(misc_info, key_mapping_options):
1130 for s, d in key_mapping_options:
1131 if s is None: # -d option
1132 devkey = misc_info.get("default_system_dev_certificate",
Dan Willemsen0ab1be62019-04-09 21:35:37 -07001133 "build/make/target/product/security/testkey")
Doug Zongker831840e2011-09-22 10:28:04 -07001134 devkeydir = os.path.dirname(devkey)
1135
1136 OPTIONS.key_map.update({
1137 devkeydir + "/testkey": d + "/releasekey",
1138 devkeydir + "/devkey": d + "/releasekey",
1139 devkeydir + "/media": d + "/media",
1140 devkeydir + "/shared": d + "/shared",
1141 devkeydir + "/platform": d + "/platform",
Oleh Cherpak982e6082019-12-10 12:58:54 +02001142 devkeydir + "/networkstack": d + "/networkstack",
Kelvin Zhang7cab7502021-08-02 19:58:14 -04001143 })
Doug Zongker831840e2011-09-22 10:28:04 -07001144 else:
1145 OPTIONS.key_map[s] = d
1146
1147
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001148def GetApiLevelAndCodename(input_tf_zip):
Tao Baoa3705452019-06-24 15:33:41 -07001149 data = input_tf_zip.read("SYSTEM/build.prop").decode()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001150 api_level = None
1151 codename = None
1152 for line in data.split("\n"):
1153 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001154 if line and line[0] != '#' and "=" in line:
1155 key, value = line.split("=", 1)
1156 key = key.strip()
1157 if key == "ro.build.version.sdk":
1158 api_level = int(value.strip())
1159 elif key == "ro.build.version.codename":
1160 codename = value.strip()
1161
1162 if api_level is None:
1163 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
1164 if codename is None:
1165 raise ValueError("No ro.build.version.codename in SYSTEM/build.prop")
1166
1167 return (api_level, codename)
1168
1169
1170def GetCodenameToApiLevelMap(input_tf_zip):
Tao Baoa3705452019-06-24 15:33:41 -07001171 data = input_tf_zip.read("SYSTEM/build.prop").decode()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001172 api_level = None
1173 codenames = None
1174 for line in data.split("\n"):
1175 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001176 if line and line[0] != '#' and "=" in line:
1177 key, value = line.split("=", 1)
1178 key = key.strip()
1179 if key == "ro.build.version.sdk":
1180 api_level = int(value.strip())
1181 elif key == "ro.build.version.all_codenames":
1182 codenames = value.strip().split(",")
1183
1184 if api_level is None:
1185 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
1186 if codenames is None:
1187 raise ValueError("No ro.build.version.all_codenames in SYSTEM/build.prop")
1188
Tao Baoa3705452019-06-24 15:33:41 -07001189 result = {}
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001190 for codename in codenames:
1191 codename = codename.strip()
Tao Baobadceb22019-03-15 09:33:43 -07001192 if codename:
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001193 result[codename] = api_level
1194 return result
1195
1196
Tao Baoaa7e9932019-03-15 09:37:01 -07001197def ReadApexKeysInfo(tf_zip):
1198 """Parses the APEX keys info from a given target-files zip.
1199
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001200 Given a target-files ZipFile, parses the META/apexkeys.txt entry and returns a
1201 dict that contains the mapping from APEX names (e.g. com.android.tzdata) to a
1202 tuple of (payload_key, container_key, sign_tool).
Tao Baoaa7e9932019-03-15 09:37:01 -07001203
1204 Args:
1205 tf_zip: The input target_files ZipFile (already open).
1206
1207 Returns:
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001208 (payload_key, container_key, sign_tool):
Jooyung Han8caba5e2021-10-27 03:58:09 +09001209 - payload_key contains the path to the payload signing key
1210 - container_key contains the path to the container signing key
1211 - sign_tool is an apex-specific signing tool for its payload contents
Tao Baoaa7e9932019-03-15 09:37:01 -07001212 """
1213 keys = {}
Tao Baoa3705452019-06-24 15:33:41 -07001214 for line in tf_zip.read('META/apexkeys.txt').decode().split('\n'):
Tao Baoaa7e9932019-03-15 09:37:01 -07001215 line = line.strip()
1216 if not line:
1217 continue
1218 matches = re.match(
1219 r'^name="(?P<NAME>.*)"\s+'
1220 r'public_key="(?P<PAYLOAD_PUBLIC_KEY>.*)"\s+'
1221 r'private_key="(?P<PAYLOAD_PRIVATE_KEY>.*)"\s+'
1222 r'container_certificate="(?P<CONTAINER_CERT>.*)"\s+'
Bill Peckham5c7b0342020-04-03 15:36:23 -07001223 r'container_private_key="(?P<CONTAINER_PRIVATE_KEY>.*?)"'
Jooyung Han8caba5e2021-10-27 03:58:09 +09001224 r'(\s+partition="(?P<PARTITION>.*?)")?'
1225 r'(\s+sign_tool="(?P<SIGN_TOOL>.*?)")?$',
Tao Baoaa7e9932019-03-15 09:37:01 -07001226 line)
1227 if not matches:
1228 continue
1229
1230 name = matches.group('NAME')
Tao Baoaa7e9932019-03-15 09:37:01 -07001231 payload_private_key = matches.group("PAYLOAD_PRIVATE_KEY")
1232
1233 def CompareKeys(pubkey, pubkey_suffix, privkey, privkey_suffix):
1234 pubkey_suffix_len = len(pubkey_suffix)
1235 privkey_suffix_len = len(privkey_suffix)
1236 return (pubkey.endswith(pubkey_suffix) and
1237 privkey.endswith(privkey_suffix) and
1238 pubkey[:-pubkey_suffix_len] == privkey[:-privkey_suffix_len])
1239
Ivan Lozanob021b2a2020-07-28 09:31:06 -04001240 # Check the container key names, as we'll carry them without the
Tao Bao6d9e3da2019-03-26 12:59:25 -07001241 # extensions. This doesn't apply to payload keys though, which we will use
1242 # full names only.
Tao Baoaa7e9932019-03-15 09:37:01 -07001243 container_cert = matches.group("CONTAINER_CERT")
1244 container_private_key = matches.group("CONTAINER_PRIVATE_KEY")
Tao Baof454c3a2019-04-24 23:53:42 -07001245 if container_cert == 'PRESIGNED' and container_private_key == 'PRESIGNED':
1246 container_key = 'PRESIGNED'
1247 elif CompareKeys(
Kelvin Zhang7cab7502021-08-02 19:58:14 -04001248 container_cert, OPTIONS.public_key_suffix,
1249 container_private_key, OPTIONS.private_key_suffix):
Tao Baof454c3a2019-04-24 23:53:42 -07001250 container_key = container_cert[:-len(OPTIONS.public_key_suffix)]
1251 else:
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001252 raise ValueError("Failed to parse container keys: \n{}".format(line))
Tao Baoaa7e9932019-03-15 09:37:01 -07001253
Jooyung Han8caba5e2021-10-27 03:58:09 +09001254 sign_tool = matches.group("SIGN_TOOL")
1255 keys[name] = (payload_private_key, container_key, sign_tool)
Tao Baoaa7e9932019-03-15 09:37:01 -07001256
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001257 return keys
Tao Baoaa7e9932019-03-15 09:37:01 -07001258
1259
Daniel Norman78554ea2021-09-14 10:29:38 -07001260def BuildVendorPartitions(output_zip_path):
1261 """Builds OPTIONS.vendor_partitions using OPTIONS.vendor_otatools."""
1262 if OPTIONS.vendor_partitions.difference(ALLOWED_VENDOR_PARTITIONS):
1263 logger.warning("Allowed --vendor_partitions: %s",
1264 ",".join(ALLOWED_VENDOR_PARTITIONS))
1265 OPTIONS.vendor_partitions = ALLOWED_VENDOR_PARTITIONS.intersection(
1266 OPTIONS.vendor_partitions)
1267
1268 logger.info("Building vendor partitions using vendor otatools.")
1269 vendor_tempdir = common.UnzipTemp(output_zip_path, [
1270 "META/*",
Po Hu0663ae42021-09-27 12:59:06 +08001271 "SYSTEM/build.prop",
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001272 "RECOVERY/*",
1273 "BOOT/*",
1274 "OTA/",
Daniel Norman78554ea2021-09-14 10:29:38 -07001275 ] + ["{}/*".format(p.upper()) for p in OPTIONS.vendor_partitions])
1276
1277 # Disable various partitions that build based on misc_info fields.
1278 # Only partitions in ALLOWED_VENDOR_PARTITIONS can be rebuilt using
1279 # vendor otatools. These other partitions will be rebuilt using the main
1280 # otatools if necessary.
1281 vendor_misc_info_path = os.path.join(vendor_tempdir, "META/misc_info.txt")
1282 vendor_misc_info = common.LoadDictionaryFromFile(vendor_misc_info_path)
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001283 # Ignore if not rebuilding recovery
1284 if not OPTIONS.rebuild_recovery:
1285 vendor_misc_info["no_boot"] = "true" # boot
1286 vendor_misc_info["vendor_boot"] = "false" # vendor_boot
1287 vendor_misc_info["no_recovery"] = "true" # recovery
Iavor-Valentin Iftime40adb172022-04-19 18:17:56 +00001288 vendor_misc_info["avb_enable"] = "false" # vbmeta
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001289
Daniel Norman78554ea2021-09-14 10:29:38 -07001290 vendor_misc_info["has_dtbo"] = "false" # dtbo
1291 vendor_misc_info["has_pvmfw"] = "false" # pvmfw
Ray-cy.leee97e0cb2023-06-27 11:44:46 +08001292 vendor_misc_info["avb_custom_images_partition_list"] = "" # avb custom images
Iavor-Valentin Iftime40adb172022-04-19 18:17:56 +00001293 vendor_misc_info["avb_building_vbmeta_image"] = "false" # skip building vbmeta
Ray-cy.leee97e0cb2023-06-27 11:44:46 +08001294 vendor_misc_info["custom_images_partition_list"] = "" # custom images
Daniel Norman78554ea2021-09-14 10:29:38 -07001295 vendor_misc_info["use_dynamic_partitions"] = "false" # super_empty
1296 vendor_misc_info["build_super_partition"] = "false" # super split
jiangxu52d8a4cb2022-09-16 14:55:17 +08001297 vendor_misc_info["avb_vbmeta_system"] = "" # skip building vbmeta_system
Daniel Norman78554ea2021-09-14 10:29:38 -07001298 with open(vendor_misc_info_path, "w") as output:
1299 for key in sorted(vendor_misc_info):
1300 output.write("{}={}\n".format(key, vendor_misc_info[key]))
1301
Po Hu0663ae42021-09-27 12:59:06 +08001302 # Disable system partition by a placeholder of IMAGES/system.img,
1303 # instead of removing SYSTEM folder.
1304 # Because SYSTEM/build.prop is still needed for:
1305 # add_img_to_target_files.CreateImage ->
1306 # common.BuildInfo ->
1307 # common.BuildInfo.CalculateFingerprint
1308 vendor_images_path = os.path.join(vendor_tempdir, "IMAGES")
1309 if not os.path.exists(vendor_images_path):
1310 os.makedirs(vendor_images_path)
1311 with open(os.path.join(vendor_images_path, "system.img"), "w") as output:
1312 pass
1313
Daniel Norman78554ea2021-09-14 10:29:38 -07001314 # Disable care_map.pb as not all ab_partitions are available when
1315 # vendor otatools regenerates vendor images.
Po Hu0663ae42021-09-27 12:59:06 +08001316 if os.path.exists(os.path.join(vendor_tempdir, "META/ab_partitions.txt")):
1317 os.remove(os.path.join(vendor_tempdir, "META/ab_partitions.txt"))
1318 # Disable RADIO images
1319 if os.path.exists(os.path.join(vendor_tempdir, "META/pack_radioimages.txt")):
1320 os.remove(os.path.join(vendor_tempdir, "META/pack_radioimages.txt"))
Daniel Norman78554ea2021-09-14 10:29:38 -07001321
1322 # Build vendor images using vendor otatools.
Iavor-Valentin Iftime63cde0f2022-03-04 16:02:44 +00001323 # Accept either a zip file or extracted directory.
1324 if os.path.isfile(OPTIONS.vendor_otatools):
1325 vendor_otatools_dir = common.MakeTempDir(prefix="vendor_otatools_")
1326 common.UnzipToDir(OPTIONS.vendor_otatools, vendor_otatools_dir)
1327 else:
1328 vendor_otatools_dir = OPTIONS.vendor_otatools
Daniel Norman78554ea2021-09-14 10:29:38 -07001329 cmd = [
1330 os.path.join(vendor_otatools_dir, "bin", "add_img_to_target_files"),
1331 "--is_signing",
Po Hu0663ae42021-09-27 12:59:06 +08001332 "--add_missing",
Daniel Norman78554ea2021-09-14 10:29:38 -07001333 "--verbose",
1334 vendor_tempdir,
1335 ]
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001336 if OPTIONS.rebuild_recovery:
1337 cmd.insert(4, "--rebuild_recovery")
1338
Daniel Norman78554ea2021-09-14 10:29:38 -07001339 common.RunAndCheckOutput(cmd, verbose=True)
1340
1341 logger.info("Writing vendor partitions to output archive.")
1342 with zipfile.ZipFile(
1343 output_zip_path, "a", compression=zipfile.ZIP_DEFLATED,
1344 allowZip64=True) as output_zip:
1345 for p in OPTIONS.vendor_partitions:
Iavor-Valentin Iftime880e4432022-03-17 14:02:27 +00001346 img_file_path = "IMAGES/{}.img".format(p)
1347 map_file_path = "IMAGES/{}.map".format(p)
1348 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, img_file_path), img_file_path)
jiangxu5b67b0d52022-06-03 14:46:56 +08001349 if os.path.exists(os.path.join(vendor_tempdir, map_file_path)):
1350 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, map_file_path), map_file_path)
Iavor-Valentin Iftime40adb172022-04-19 18:17:56 +00001351 # copy recovery.img, boot.img, recovery patch & install.sh
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001352 if OPTIONS.rebuild_recovery:
Iavor-Valentin Iftime40adb172022-04-19 18:17:56 +00001353 recovery_img = "IMAGES/recovery.img"
1354 boot_img = "IMAGES/boot.img"
1355 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, recovery_img), recovery_img)
1356 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, boot_img), boot_img)
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001357 recovery_patch_path = "VENDOR/recovery-from-boot.p"
1358 recovery_sh_path = "VENDOR/bin/install-recovery.sh"
1359 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, recovery_patch_path), recovery_patch_path)
1360 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, recovery_sh_path), recovery_sh_path)
Daniel Norman78554ea2021-09-14 10:29:38 -07001361
1362
Doug Zongkereef39442009-04-02 12:14:19 -07001363def main(argv):
1364
Doug Zongker831840e2011-09-22 10:28:04 -07001365 key_mapping_options = []
1366
Doug Zongkereef39442009-04-02 12:14:19 -07001367 def option_handler(o, a):
Doug Zongker05d3dea2009-06-22 11:32:31 -07001368 if o in ("-e", "--extra_apks"):
Doug Zongkereef39442009-04-02 12:14:19 -07001369 names, key = a.split("=")
1370 names = names.split(",")
1371 for n in names:
1372 OPTIONS.extra_apks[n] = key
Tao Baoaa7e9932019-03-15 09:37:01 -07001373 elif o == "--extra_apex_payload_key":
Kelvin Zhang085b6f32022-07-25 16:12:30 -07001374 apex_names, key = a.split("=")
Kelvin Zhang87e45272022-07-27 11:14:12 -07001375 for name in apex_names.split(","):
Kelvin Zhang085b6f32022-07-25 16:12:30 -07001376 OPTIONS.extra_apex_payload_keys[name] = key
Tao Bao93c2a012018-06-19 12:19:35 -07001377 elif o == "--skip_apks_with_path_prefix":
Tianjiea85bdf02020-07-29 11:56:19 -07001378 # Check the prefix, which must be in all upper case.
Tao Bao93c2a012018-06-19 12:19:35 -07001379 prefix = a.split('/')[0]
1380 if not prefix or prefix != prefix.upper():
1381 raise ValueError("Invalid path prefix '%s'" % (a,))
1382 OPTIONS.skip_apks_with_path_prefix.add(a)
Doug Zongkereef39442009-04-02 12:14:19 -07001383 elif o in ("-d", "--default_key_mappings"):
Doug Zongker831840e2011-09-22 10:28:04 -07001384 key_mapping_options.append((None, a))
Doug Zongkereef39442009-04-02 12:14:19 -07001385 elif o in ("-k", "--key_mapping"):
Doug Zongker831840e2011-09-22 10:28:04 -07001386 key_mapping_options.append(a.split("=", 1))
Doug Zongker8e931bf2009-04-06 15:21:45 -07001387 elif o in ("-o", "--replace_ota_keys"):
1388 OPTIONS.replace_ota_keys = True
Doug Zongkerae877012009-04-21 10:04:51 -07001389 elif o in ("-t", "--tag_changes"):
1390 new = []
1391 for i in a.split(","):
1392 i = i.strip()
1393 if not i or i[0] not in "-+":
1394 raise ValueError("Bad tag change '%s'" % (i,))
1395 new.append(i[0] + i[1:].strip())
1396 OPTIONS.tag_changes = tuple(new)
Geremy Condraf19b3652014-07-29 17:54:54 -07001397 elif o == "--replace_verity_public_key":
hungweichendd3fca02022-08-19 06:33:25 +00001398 raise ValueError("--replace_verity_public_key is no longer supported,"
1399 " please switch to AVB")
Geremy Condraf19b3652014-07-29 17:54:54 -07001400 elif o == "--replace_verity_private_key":
hungweichendd3fca02022-08-19 06:33:25 +00001401 raise ValueError("--replace_verity_private_key is no longer supported,"
1402 " please switch to AVB")
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001403 elif o == "--replace_verity_keyid":
hungweichendd3fca02022-08-19 06:33:25 +00001404 raise ValueError("--replace_verity_keyid is no longer supported, please"
1405 " switch to AVB")
Bowgo Tsai2fe786a2020-02-21 17:48:18 +08001406 elif o == "--remove_avb_public_keys":
1407 OPTIONS.remove_avb_public_keys = a.split(",")
Tao Bao639118f2017-06-19 15:48:02 -07001408 elif o == "--avb_vbmeta_key":
1409 OPTIONS.avb_keys['vbmeta'] = a
1410 elif o == "--avb_vbmeta_algorithm":
1411 OPTIONS.avb_algorithms['vbmeta'] = a
1412 elif o == "--avb_vbmeta_extra_args":
1413 OPTIONS.avb_extra_args['vbmeta'] = a
1414 elif o == "--avb_boot_key":
1415 OPTIONS.avb_keys['boot'] = a
1416 elif o == "--avb_boot_algorithm":
1417 OPTIONS.avb_algorithms['boot'] = a
1418 elif o == "--avb_boot_extra_args":
1419 OPTIONS.avb_extra_args['boot'] = a
1420 elif o == "--avb_dtbo_key":
1421 OPTIONS.avb_keys['dtbo'] = a
1422 elif o == "--avb_dtbo_algorithm":
1423 OPTIONS.avb_algorithms['dtbo'] = a
1424 elif o == "--avb_dtbo_extra_args":
1425 OPTIONS.avb_extra_args['dtbo'] = a
Hongguang Chen0d6b7272022-11-07 13:36:38 -08001426 elif o == "--avb_init_boot_key":
1427 OPTIONS.avb_keys['init_boot'] = a
1428 elif o == "--avb_init_boot_algorithm":
1429 OPTIONS.avb_algorithms['init_boot'] = a
1430 elif o == "--avb_init_boot_extra_args":
1431 OPTIONS.avb_extra_args['init_boot'] = a
Ben Fennema6082d0a2021-12-11 14:03:10 -08001432 elif o == "--avb_recovery_key":
1433 OPTIONS.avb_keys['recovery'] = a
1434 elif o == "--avb_recovery_algorithm":
1435 OPTIONS.avb_algorithms['recovery'] = a
1436 elif o == "--avb_recovery_extra_args":
1437 OPTIONS.avb_extra_args['recovery'] = a
Tao Bao639118f2017-06-19 15:48:02 -07001438 elif o == "--avb_system_key":
1439 OPTIONS.avb_keys['system'] = a
1440 elif o == "--avb_system_algorithm":
1441 OPTIONS.avb_algorithms['system'] = a
1442 elif o == "--avb_system_extra_args":
1443 OPTIONS.avb_extra_args['system'] = a
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001444 elif o == "--avb_system_other_key":
1445 OPTIONS.avb_keys['system_other'] = a
1446 elif o == "--avb_system_other_algorithm":
1447 OPTIONS.avb_algorithms['system_other'] = a
1448 elif o == "--avb_system_other_extra_args":
1449 OPTIONS.avb_extra_args['system_other'] = a
Tao Bao639118f2017-06-19 15:48:02 -07001450 elif o == "--avb_vendor_key":
1451 OPTIONS.avb_keys['vendor'] = a
1452 elif o == "--avb_vendor_algorithm":
1453 OPTIONS.avb_algorithms['vendor'] = a
1454 elif o == "--avb_vendor_extra_args":
1455 OPTIONS.avb_extra_args['vendor'] = a
Tao Baod6085d62019-05-06 12:55:42 -07001456 elif o == "--avb_vbmeta_system_key":
1457 OPTIONS.avb_keys['vbmeta_system'] = a
1458 elif o == "--avb_vbmeta_system_algorithm":
1459 OPTIONS.avb_algorithms['vbmeta_system'] = a
1460 elif o == "--avb_vbmeta_system_extra_args":
1461 OPTIONS.avb_extra_args['vbmeta_system'] = a
1462 elif o == "--avb_vbmeta_vendor_key":
1463 OPTIONS.avb_keys['vbmeta_vendor'] = a
1464 elif o == "--avb_vbmeta_vendor_algorithm":
1465 OPTIONS.avb_algorithms['vbmeta_vendor'] = a
1466 elif o == "--avb_vbmeta_vendor_extra_args":
1467 OPTIONS.avb_extra_args['vbmeta_vendor'] = a
Tao Baoaa7e9932019-03-15 09:37:01 -07001468 elif o == "--avb_apex_extra_args":
1469 OPTIONS.avb_extra_args['apex'] = a
Hongguang Chenf23364d2020-04-27 18:36:36 -07001470 elif o == "--avb_extra_custom_image_key":
1471 partition, key = a.split("=")
1472 OPTIONS.avb_keys[partition] = key
1473 elif o == "--avb_extra_custom_image_algorithm":
1474 partition, algorithm = a.split("=")
1475 OPTIONS.avb_algorithms[partition] = algorithm
1476 elif o == "--avb_extra_custom_image_extra_args":
Hongguang Chen883eecb2020-05-23 22:20:19 -07001477 # Setting the maxsplit parameter to one, which will return a list with
1478 # two elements. e.g., the second '=' should not be splitted for
1479 # 'oem=--signing_helper_with_files=/tmp/avbsigner.sh'.
1480 partition, extra_args = a.split("=", 1)
Hongguang Chenf23364d2020-04-27 18:36:36 -07001481 OPTIONS.avb_extra_args[partition] = extra_args
Bowgo Tsai27c39b02021-03-12 21:40:32 +08001482 elif o == "--gki_signing_key":
1483 OPTIONS.gki_signing_key = a
1484 elif o == "--gki_signing_algorithm":
1485 OPTIONS.gki_signing_algorithm = a
1486 elif o == "--gki_signing_extra_args":
1487 OPTIONS.gki_signing_extra_args = a
Daniel Norman78554ea2021-09-14 10:29:38 -07001488 elif o == "--vendor_otatools":
1489 OPTIONS.vendor_otatools = a
1490 elif o == "--vendor_partitions":
1491 OPTIONS.vendor_partitions = set(a.split(","))
Bowgo Tsai2a781692021-10-13 17:39:33 +08001492 elif o == "--allow_gsi_debug_sepolicy":
1493 OPTIONS.allow_gsi_debug_sepolicy = True
Kelvin Zhange50bb512022-08-01 15:58:51 -07001494 elif o == "--override_apk_keys":
1495 OPTIONS.override_apk_keys = a
1496 elif o == "--override_apex_keys":
1497 OPTIONS.override_apex_keys = a
Doug Zongkereef39442009-04-02 12:14:19 -07001498 else:
1499 return False
1500 return True
1501
Tao Bao639118f2017-06-19 15:48:02 -07001502 args = common.ParseOptions(
1503 argv, __doc__,
1504 extra_opts="e:d:k:ot:",
1505 extra_long_opts=[
Tao Bao0c28d2d2017-12-24 10:37:38 -08001506 "extra_apks=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001507 "extra_apex_payload_key=",
Tao Bao93c2a012018-06-19 12:19:35 -07001508 "skip_apks_with_path_prefix=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001509 "default_key_mappings=",
1510 "key_mapping=",
1511 "replace_ota_keys",
1512 "tag_changes=",
1513 "replace_verity_public_key=",
1514 "replace_verity_private_key=",
1515 "replace_verity_keyid=",
Bowgo Tsai2fe786a2020-02-21 17:48:18 +08001516 "remove_avb_public_keys=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001517 "avb_apex_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001518 "avb_vbmeta_algorithm=",
1519 "avb_vbmeta_key=",
1520 "avb_vbmeta_extra_args=",
1521 "avb_boot_algorithm=",
1522 "avb_boot_key=",
1523 "avb_boot_extra_args=",
1524 "avb_dtbo_algorithm=",
1525 "avb_dtbo_key=",
1526 "avb_dtbo_extra_args=",
Hongguang Chen0d6b7272022-11-07 13:36:38 -08001527 "avb_init_boot_algorithm=",
1528 "avb_init_boot_key=",
1529 "avb_init_boot_extra_args=",
Ben Fennema6082d0a2021-12-11 14:03:10 -08001530 "avb_recovery_algorithm=",
1531 "avb_recovery_key=",
1532 "avb_recovery_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001533 "avb_system_algorithm=",
1534 "avb_system_key=",
1535 "avb_system_extra_args=",
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001536 "avb_system_other_algorithm=",
1537 "avb_system_other_key=",
1538 "avb_system_other_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001539 "avb_vendor_algorithm=",
1540 "avb_vendor_key=",
1541 "avb_vendor_extra_args=",
Tao Baod6085d62019-05-06 12:55:42 -07001542 "avb_vbmeta_system_algorithm=",
1543 "avb_vbmeta_system_key=",
1544 "avb_vbmeta_system_extra_args=",
1545 "avb_vbmeta_vendor_algorithm=",
1546 "avb_vbmeta_vendor_key=",
1547 "avb_vbmeta_vendor_extra_args=",
Hongguang Chenf23364d2020-04-27 18:36:36 -07001548 "avb_extra_custom_image_key=",
1549 "avb_extra_custom_image_algorithm=",
1550 "avb_extra_custom_image_extra_args=",
Bowgo Tsai27c39b02021-03-12 21:40:32 +08001551 "gki_signing_key=",
1552 "gki_signing_algorithm=",
1553 "gki_signing_extra_args=",
Daniel Norman78554ea2021-09-14 10:29:38 -07001554 "vendor_partitions=",
1555 "vendor_otatools=",
Bowgo Tsai2a781692021-10-13 17:39:33 +08001556 "allow_gsi_debug_sepolicy",
Kelvin Zhange50bb512022-08-01 15:58:51 -07001557 "override_apk_keys=",
1558 "override_apex_keys=",
Tao Bao639118f2017-06-19 15:48:02 -07001559 ],
Kelvin Zhangb84d2aa2023-11-06 10:53:41 -08001560 extra_option_handler=[option_handler, payload_signer.signer_options])
Doug Zongkereef39442009-04-02 12:14:19 -07001561
1562 if len(args) != 2:
1563 common.Usage(__doc__)
1564 sys.exit(1)
1565
Tao Baobadceb22019-03-15 09:33:43 -07001566 common.InitLogging()
1567
Kelvin Zhang928c2342020-09-22 16:15:57 -04001568 input_zip = zipfile.ZipFile(args[0], "r", allowZip64=True)
Tao Bao2b8f4892017-06-13 12:54:58 -07001569 output_zip = zipfile.ZipFile(args[1], "w",
1570 compression=zipfile.ZIP_DEFLATED,
1571 allowZip64=True)
Doug Zongkereef39442009-04-02 12:14:19 -07001572
Doug Zongker831840e2011-09-22 10:28:04 -07001573 misc_info = common.LoadInfoDict(input_zip)
Kelvin Zhangb84d2aa2023-11-06 10:53:41 -08001574 if OPTIONS.package_key is None:
1575 OPTIONS.package_key = misc_info.get(
1576 "default_system_dev_certificate",
1577 "build/make/target/product/security/testkey")
Doug Zongker831840e2011-09-22 10:28:04 -07001578
1579 BuildKeyMap(misc_info, key_mapping_options)
1580
Tao Baoaa7e9932019-03-15 09:37:01 -07001581 apk_keys_info, compressed_extension = common.ReadApkCerts(input_zip)
1582 apk_keys = GetApkCerts(apk_keys_info)
Doug Zongkereb338ef2009-05-20 16:50:49 -07001583
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001584 apex_keys_info = ReadApexKeysInfo(input_zip)
Tao Baoaa7e9932019-03-15 09:37:01 -07001585 apex_keys = GetApexKeys(apex_keys_info, apk_keys)
1586
Tianjie Xu88a759d2020-01-23 10:47:54 -08001587 # TODO(xunchang) check for the apks inside the apex files, and abort early if
1588 # the keys are not available.
Tao Baoaa7e9932019-03-15 09:37:01 -07001589 CheckApkAndApexKeysAvailable(
1590 input_zip,
1591 set(apk_keys.keys()) | set(apex_keys.keys()),
Tao Baoe1343992019-03-19 12:24:03 -07001592 compressed_extension,
1593 apex_keys)
Tao Baoaa7e9932019-03-15 09:37:01 -07001594
1595 key_passwords = common.GetKeyPasswords(
1596 set(apk_keys.values()) | set(itertools.chain(*apex_keys.values())))
Tao Bao9aa4b9b2016-09-29 17:53:56 -07001597 platform_api_level, _ = GetApiLevelAndCodename(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001598 codename_to_api_level_map = GetCodenameToApiLevelMap(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001599
Doug Zongker412c02f2014-02-13 10:58:24 -08001600 ProcessTargetFiles(input_zip, output_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -07001601 apk_keys, apex_keys, key_passwords,
1602 platform_api_level, codename_to_api_level_map,
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001603 compressed_extension)
Doug Zongker8e931bf2009-04-06 15:21:45 -07001604
Kelvin Zhangf92f7f02023-04-14 21:32:54 +00001605 common.ZipClose(input_zip)
1606 common.ZipClose(output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001607
Daniel Norman78554ea2021-09-14 10:29:38 -07001608 if OPTIONS.vendor_partitions and OPTIONS.vendor_otatools:
1609 BuildVendorPartitions(args[1])
1610
Tianjie Xub48589a2016-08-03 19:21:52 -07001611 # Skip building userdata.img and cache.img when signing the target files.
Daniel Norman78554ea2021-09-14 10:29:38 -07001612 new_args = ["--is_signing", "--add_missing", "--verbose"]
Tianjie Xu616fbeb2017-05-23 14:51:02 -07001613 # add_img_to_target_files builds the system image from scratch, so the
1614 # recovery patch is guaranteed to be regenerated there.
1615 if OPTIONS.rebuild_recovery:
1616 new_args.append("--rebuild_recovery")
1617 new_args.append(args[1])
Tianjie Xub48589a2016-08-03 19:21:52 -07001618 add_img_to_target_files.main(new_args)
Doug Zongker3c84f562014-07-31 11:06:30 -07001619
Tao Bao0c28d2d2017-12-24 10:37:38 -08001620 print("done.")
Doug Zongkereef39442009-04-02 12:14:19 -07001621
1622
1623if __name__ == '__main__':
1624 try:
1625 main(sys.argv[1:])
Tao Bao639118f2017-06-19 15:48:02 -07001626 finally:
1627 common.Cleanup()