blob: 00acd980ed5562b39a45c2a3259cb9f255904ee4 [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
Tianjie Xu88a759d2020-01-23 10:47:54 -0800126 --android_jar_path <path>
127 Path to the android.jar to repack the apex file.
Doug Zongkereef39442009-04-02 12:14:19 -0700128"""
129
Tao Bao0c28d2d2017-12-24 10:37:38 -0800130from __future__ import print_function
Doug Zongkereef39442009-04-02 12:14:19 -0700131
Robert Craig817c5742013-04-19 10:59:22 -0400132import base64
Doug Zongker8e931bf2009-04-06 15:21:45 -0700133import copy
Robert Craig817c5742013-04-19 10:59:22 -0400134import errno
Narayan Kamatha07bf042017-08-14 14:49:21 +0100135import gzip
Tao Baobb733882019-07-24 23:31:19 -0700136import io
Tao Baoaa7e9932019-03-15 09:37:01 -0700137import itertools
Tao Baobadceb22019-03-15 09:33:43 -0700138import logging
Doug Zongkereef39442009-04-02 12:14:19 -0700139import os
140import re
Narayan Kamatha07bf042017-08-14 14:49:21 +0100141import shutil
Tao Bao9fdd00f2017-07-12 11:57:05 -0700142import stat
Doug Zongkereef39442009-04-02 12:14:19 -0700143import subprocess
Tao Bao0c28d2d2017-12-24 10:37:38 -0800144import sys
Doug Zongkereef39442009-04-02 12:14:19 -0700145import tempfile
146import zipfile
Tao Bao66472632017-12-04 17:16:36 -0800147from xml.etree import ElementTree
Doug Zongkereef39442009-04-02 12:14:19 -0700148
Doug Zongker3c84f562014-07-31 11:06:30 -0700149import add_img_to_target_files
Tao Baoaa7e9932019-03-15 09:37:01 -0700150import apex_utils
Doug Zongkereef39442009-04-02 12:14:19 -0700151import common
152
Tao Bao0c28d2d2017-12-24 10:37:38 -0800153
154if sys.hexversion < 0x02070000:
155 print("Python 2.7 or newer is required.", file=sys.stderr)
156 sys.exit(1)
157
158
Tao Baobadceb22019-03-15 09:33:43 -0700159logger = logging.getLogger(__name__)
160
Doug Zongkereef39442009-04-02 12:14:19 -0700161OPTIONS = common.OPTIONS
162
163OPTIONS.extra_apks = {}
Tao Baoaa7e9932019-03-15 09:37:01 -0700164OPTIONS.extra_apex_payload_keys = {}
Tao Bao93c2a012018-06-19 12:19:35 -0700165OPTIONS.skip_apks_with_path_prefix = set()
Doug Zongkereef39442009-04-02 12:14:19 -0700166OPTIONS.key_map = {}
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700167OPTIONS.rebuild_recovery = False
Doug Zongker8e931bf2009-04-06 15:21:45 -0700168OPTIONS.replace_ota_keys = False
Geremy Condraf19b3652014-07-29 17:54:54 -0700169OPTIONS.replace_verity_public_key = False
170OPTIONS.replace_verity_private_key = False
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700171OPTIONS.replace_verity_keyid = False
Bowgo Tsai2fe786a2020-02-21 17:48:18 +0800172OPTIONS.remove_avb_public_keys = None
Doug Zongker831840e2011-09-22 10:28:04 -0700173OPTIONS.tag_changes = ("-test-keys", "-dev-keys", "+release-keys")
Tao Bao639118f2017-06-19 15:48:02 -0700174OPTIONS.avb_keys = {}
175OPTIONS.avb_algorithms = {}
176OPTIONS.avb_extra_args = {}
Tianjie Xu88a759d2020-01-23 10:47:54 -0800177OPTIONS.android_jar_path = None
Doug Zongkereef39442009-04-02 12:14:19 -0700178
Tao Bao0c28d2d2017-12-24 10:37:38 -0800179
Tao Bao19b02fe2019-10-09 00:04:28 -0700180AVB_FOOTER_ARGS_BY_PARTITION = {
Tianjiebf0b8a82021-03-03 17:31:04 -0800181 'boot': 'avb_boot_add_hash_footer_args',
182 'dtbo': 'avb_dtbo_add_hash_footer_args',
183 'product': 'avb_product_add_hashtree_footer_args',
184 'recovery': 'avb_recovery_add_hash_footer_args',
185 'system': 'avb_system_add_hashtree_footer_args',
186 'system_ext': 'avb_system_ext_add_hashtree_footer_args',
187 'system_other': 'avb_system_other_add_hashtree_footer_args',
188 'odm': 'avb_odm_add_hashtree_footer_args',
189 'odm_dlkm': 'avb_odm_dlkm_add_hashtree_footer_args',
190 'pvmfw': 'avb_pvmfw_add_hash_footer_args',
191 'vendor': 'avb_vendor_add_hashtree_footer_args',
192 'vendor_boot': 'avb_vendor_boot_add_hash_footer_args',
193 'vendor_dlkm': "avb_vendor_dlkm_add_hashtree_footer_args",
194 'vbmeta': 'avb_vbmeta_args',
195 'vbmeta_system': 'avb_vbmeta_system_args',
196 'vbmeta_vendor': 'avb_vbmeta_vendor_args',
Tao Bao19b02fe2019-10-09 00:04:28 -0700197}
198
199
Tianjiebf0b8a82021-03-03 17:31:04 -0800200# Check that AVB_FOOTER_ARGS_BY_PARTITION is in sync with AVB_PARTITIONS.
201for partition in common.AVB_PARTITIONS:
202 if partition not in AVB_FOOTER_ARGS_BY_PARTITION:
203 raise RuntimeError("Missing {} in AVB_FOOTER_ARGS".format(partition))
204
205
Narayan Kamatha07bf042017-08-14 14:49:21 +0100206def GetApkCerts(certmap):
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800207 # apply the key remapping to the contents of the file
Tao Baoa3705452019-06-24 15:33:41 -0700208 for apk, cert in certmap.items():
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800209 certmap[apk] = OPTIONS.key_map.get(cert, cert)
210
211 # apply all the -e options, overriding anything in the file
Tao Baoa3705452019-06-24 15:33:41 -0700212 for apk, cert in OPTIONS.extra_apks.items():
Doug Zongkerdecf9952009-12-15 17:27:49 -0800213 if not cert:
214 cert = "PRESIGNED"
Doug Zongkerad88c7c2009-04-14 12:34:27 -0700215 certmap[apk] = OPTIONS.key_map.get(cert, cert)
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800216
Doug Zongkereef39442009-04-02 12:14:19 -0700217 return certmap
218
219
Tao Baoaa7e9932019-03-15 09:37:01 -0700220def GetApexKeys(keys_info, key_map):
221 """Gets APEX payload and container signing keys by applying the mapping rules.
222
Tao Baoe1343992019-03-19 12:24:03 -0700223 Presigned payload / container keys will be set accordingly.
Tao Baoaa7e9932019-03-15 09:37:01 -0700224
225 Args:
226 keys_info: A dict that maps from APEX filenames to a tuple of (payload_key,
227 container_key).
228 key_map: A dict that overrides the keys, specified via command-line input.
229
230 Returns:
231 A dict that contains the updated APEX key mapping, which should be used for
232 the current signing.
Tao Baof98fa102019-04-24 14:51:25 -0700233
234 Raises:
235 AssertionError: On invalid container / payload key overrides.
Tao Baoaa7e9932019-03-15 09:37:01 -0700236 """
237 # Apply all the --extra_apex_payload_key options to override the payload
238 # signing keys in the given keys_info.
239 for apex, key in OPTIONS.extra_apex_payload_keys.items():
Tao Baoe1343992019-03-19 12:24:03 -0700240 if not key:
241 key = 'PRESIGNED'
Tao Bao34223092019-07-11 11:52:52 -0700242 if apex not in keys_info:
243 logger.warning('Failed to find %s in target_files; Ignored', apex)
244 continue
Tao Baoaa7e9932019-03-15 09:37:01 -0700245 keys_info[apex] = (key, keys_info[apex][1])
246
247 # Apply the key remapping to container keys.
248 for apex, (payload_key, container_key) in keys_info.items():
249 keys_info[apex] = (payload_key, key_map.get(container_key, container_key))
250
251 # Apply all the --extra_apks options to override the container keys.
252 for apex, key in OPTIONS.extra_apks.items():
253 # Skip non-APEX containers.
254 if apex not in keys_info:
255 continue
Tao Baoe1343992019-03-19 12:24:03 -0700256 if not key:
257 key = 'PRESIGNED'
Tao Baofa9de0a2019-03-18 10:24:17 -0700258 keys_info[apex] = (keys_info[apex][0], key_map.get(key, key))
Tao Baoaa7e9932019-03-15 09:37:01 -0700259
Tao Baof98fa102019-04-24 14:51:25 -0700260 # A PRESIGNED container entails a PRESIGNED payload. Apply this to all the
261 # APEX key pairs. However, a PRESIGNED container with non-PRESIGNED payload
262 # (overridden via commandline) indicates a config error, which should not be
263 # allowed.
264 for apex, (payload_key, container_key) in keys_info.items():
265 if container_key != 'PRESIGNED':
266 continue
267 if apex in OPTIONS.extra_apex_payload_keys:
268 payload_override = OPTIONS.extra_apex_payload_keys[apex]
269 assert payload_override == '', \
270 ("Invalid APEX key overrides: {} has PRESIGNED container but "
271 "non-PRESIGNED payload key {}").format(apex, payload_override)
272 if payload_key != 'PRESIGNED':
273 print(
274 "Setting {} payload as PRESIGNED due to PRESIGNED container".format(
275 apex))
276 keys_info[apex] = ('PRESIGNED', 'PRESIGNED')
277
Tao Baoaa7e9932019-03-15 09:37:01 -0700278 return keys_info
279
280
Tao Bao93c2a012018-06-19 12:19:35 -0700281def GetApkFileInfo(filename, compressed_extension, skipped_prefixes):
Tao Bao11f955c2018-06-19 12:19:35 -0700282 """Returns the APK info based on the given filename.
283
284 Checks if the given filename (with path) looks like an APK file, by taking the
Tao Bao93c2a012018-06-19 12:19:35 -0700285 compressed extension into consideration. If it appears to be an APK file,
286 further checks if the APK file should be skipped when signing, based on the
287 given path prefixes.
Tao Bao11f955c2018-06-19 12:19:35 -0700288
289 Args:
290 filename: Path to the file.
291 compressed_extension: The extension string of compressed APKs (e.g. ".gz"),
292 or None if there's no compressed APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700293 skipped_prefixes: A set/list/tuple of the path prefixes to be skipped.
Tao Bao11f955c2018-06-19 12:19:35 -0700294
295 Returns:
Tao Bao93c2a012018-06-19 12:19:35 -0700296 (is_apk, is_compressed, should_be_skipped): is_apk indicates whether the
297 given filename is an APK file. is_compressed indicates whether the APK file
298 is compressed (only meaningful when is_apk is True). should_be_skipped
299 indicates whether the filename matches any of the given prefixes to be
300 skipped.
Tao Bao11f955c2018-06-19 12:19:35 -0700301
302 Raises:
Tao Bao93c2a012018-06-19 12:19:35 -0700303 AssertionError: On invalid compressed_extension or skipped_prefixes inputs.
Tao Bao11f955c2018-06-19 12:19:35 -0700304 """
305 assert compressed_extension is None or compressed_extension.startswith('.'), \
306 "Invalid compressed_extension arg: '{}'".format(compressed_extension)
307
Tao Bao93c2a012018-06-19 12:19:35 -0700308 # skipped_prefixes should be one of set/list/tuple types. Other types such as
309 # str shouldn't be accepted.
Tao Baobadceb22019-03-15 09:33:43 -0700310 assert isinstance(skipped_prefixes, (set, list, tuple)), \
311 "Invalid skipped_prefixes input type: {}".format(type(skipped_prefixes))
Tao Bao93c2a012018-06-19 12:19:35 -0700312
Tao Bao11f955c2018-06-19 12:19:35 -0700313 compressed_apk_extension = (
314 ".apk" + compressed_extension if compressed_extension else None)
315 is_apk = (filename.endswith(".apk") or
316 (compressed_apk_extension and
317 filename.endswith(compressed_apk_extension)))
318 if not is_apk:
Tao Bao93c2a012018-06-19 12:19:35 -0700319 return (False, False, False)
Tao Bao11f955c2018-06-19 12:19:35 -0700320
321 is_compressed = (compressed_apk_extension and
322 filename.endswith(compressed_apk_extension))
Tao Bao93c2a012018-06-19 12:19:35 -0700323 should_be_skipped = filename.startswith(tuple(skipped_prefixes))
324 return (True, is_compressed, should_be_skipped)
Tao Bao11f955c2018-06-19 12:19:35 -0700325
326
Tao Baoaa7e9932019-03-15 09:37:01 -0700327def CheckApkAndApexKeysAvailable(input_tf_zip, known_keys,
Tao Baoe1343992019-03-19 12:24:03 -0700328 compressed_extension, apex_keys):
Tao Baoaa7e9932019-03-15 09:37:01 -0700329 """Checks that all the APKs and APEXes have keys specified.
Tao Bao11f955c2018-06-19 12:19:35 -0700330
331 Args:
332 input_tf_zip: An open target_files zip file.
Tao Baoaa7e9932019-03-15 09:37:01 -0700333 known_keys: A set of APKs and APEXes that have known signing keys.
Tao Bao11f955c2018-06-19 12:19:35 -0700334 compressed_extension: The extension string of compressed APKs, such as
Tao Baoaa7e9932019-03-15 09:37:01 -0700335 '.gz', or None if there's no compressed APKs.
Tao Baoe1343992019-03-19 12:24:03 -0700336 apex_keys: A dict that contains the key mapping from APEX name to
337 (payload_key, container_key).
Tao Bao11f955c2018-06-19 12:19:35 -0700338
339 Raises:
Tao Baoaa7e9932019-03-15 09:37:01 -0700340 AssertionError: On finding unknown APKs and APEXes.
Tao Bao11f955c2018-06-19 12:19:35 -0700341 """
Tao Baoaa7e9932019-03-15 09:37:01 -0700342 unknown_files = []
Doug Zongkereb338ef2009-05-20 16:50:49 -0700343 for info in input_tf_zip.infolist():
Tianjie5bd03952021-02-18 23:02:36 -0800344 # Handle APEXes on all partitions
345 if info.filename.endswith('.apex'):
Tao Baoaa7e9932019-03-15 09:37:01 -0700346 name = os.path.basename(info.filename)
347 if name not in known_keys:
348 unknown_files.append(name)
349 continue
350
351 # And APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700352 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
353 info.filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
354 if not is_apk or should_be_skipped:
Tao Bao11f955c2018-06-19 12:19:35 -0700355 continue
Tao Baoaa7e9932019-03-15 09:37:01 -0700356
Tao Bao11f955c2018-06-19 12:19:35 -0700357 name = os.path.basename(info.filename)
358 if is_compressed:
359 name = name[:-len(compressed_extension)]
Tao Baoaa7e9932019-03-15 09:37:01 -0700360 if name not in known_keys:
361 unknown_files.append(name)
Tao Bao11f955c2018-06-19 12:19:35 -0700362
Tao Baoaa7e9932019-03-15 09:37:01 -0700363 assert not unknown_files, \
Tao Bao11f955c2018-06-19 12:19:35 -0700364 ("No key specified for:\n {}\n"
365 "Use '-e <apkname>=' to specify a key (which may be an empty string to "
Tao Baoaa7e9932019-03-15 09:37:01 -0700366 "not sign this apk).".format("\n ".join(unknown_files)))
Doug Zongkereb338ef2009-05-20 16:50:49 -0700367
Tao Baoe1343992019-03-19 12:24:03 -0700368 # For all the APEXes, double check that we won't have an APEX that has only
Tao Baof98fa102019-04-24 14:51:25 -0700369 # one of the payload / container keys set. Note that non-PRESIGNED container
370 # with PRESIGNED payload could be allowed but currently unsupported. It would
371 # require changing SignApex implementation.
Tao Baoe1343992019-03-19 12:24:03 -0700372 if not apex_keys:
373 return
374
375 invalid_apexes = []
376 for info in input_tf_zip.infolist():
Tianjie5bd03952021-02-18 23:02:36 -0800377 if not info.filename.endswith('.apex'):
Tao Baoe1343992019-03-19 12:24:03 -0700378 continue
379
380 name = os.path.basename(info.filename)
381 (payload_key, container_key) = apex_keys[name]
382 if ((payload_key in common.SPECIAL_CERT_STRINGS and
383 container_key not in common.SPECIAL_CERT_STRINGS) or
384 (payload_key not in common.SPECIAL_CERT_STRINGS and
385 container_key in common.SPECIAL_CERT_STRINGS)):
386 invalid_apexes.append(
387 "{}: payload_key {}, container_key {}".format(
388 name, payload_key, container_key))
389
390 assert not invalid_apexes, \
391 "Invalid APEX keys specified:\n {}\n".format(
392 "\n ".join(invalid_apexes))
393
Doug Zongkereb338ef2009-05-20 16:50:49 -0700394
Narayan Kamatha07bf042017-08-14 14:49:21 +0100395def SignApk(data, keyname, pw, platform_api_level, codename_to_api_level_map,
Oleg Aravin8046cb02020-06-02 16:02:38 -0700396 is_compressed, apk_name):
397 unsigned = tempfile.NamedTemporaryFile(suffix='_' + apk_name)
Doug Zongkereef39442009-04-02 12:14:19 -0700398 unsigned.write(data)
399 unsigned.flush()
400
Narayan Kamatha07bf042017-08-14 14:49:21 +0100401 if is_compressed:
402 uncompressed = tempfile.NamedTemporaryFile()
Tao Bao0c28d2d2017-12-24 10:37:38 -0800403 with gzip.open(unsigned.name, "rb") as in_file, \
404 open(uncompressed.name, "wb") as out_file:
Narayan Kamatha07bf042017-08-14 14:49:21 +0100405 shutil.copyfileobj(in_file, out_file)
406
407 # Finally, close the "unsigned" file (which is gzip compressed), and then
408 # replace it with the uncompressed version.
409 #
410 # TODO(narayan): All this nastiness can be avoided if python 3.2 is in use,
411 # we could just gzip / gunzip in-memory buffers instead.
412 unsigned.close()
413 unsigned = uncompressed
414
Oleg Aravin8046cb02020-06-02 16:02:38 -0700415 signed = tempfile.NamedTemporaryFile(suffix='_' + apk_name)
Doug Zongkereef39442009-04-02 12:14:19 -0700416
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800417 # For pre-N builds, don't upgrade to SHA-256 JAR signatures based on the APK's
418 # minSdkVersion to avoid increasing incremental OTA update sizes. If an APK
419 # didn't change, we don't want its signature to change due to the switch
420 # from SHA-1 to SHA-256.
421 # By default, APK signer chooses SHA-256 signatures if the APK's minSdkVersion
422 # is 18 or higher. For pre-N builds we disable this mechanism by pretending
423 # that the APK's minSdkVersion is 1.
424 # For N+ builds, we let APK signer rely on the APK's minSdkVersion to
425 # determine whether to use SHA-256.
426 min_api_level = None
427 if platform_api_level > 23:
428 # Let APK signer choose whether to use SHA-1 or SHA-256, based on the APK's
429 # minSdkVersion attribute
430 min_api_level = None
431 else:
432 # Force APK signer to use SHA-1
433 min_api_level = 1
434
435 common.SignFile(unsigned.name, signed.name, keyname, pw,
Tao Bao0c28d2d2017-12-24 10:37:38 -0800436 min_api_level=min_api_level,
437 codename_to_api_level_map=codename_to_api_level_map)
Doug Zongkereef39442009-04-02 12:14:19 -0700438
Tao Bao0c28d2d2017-12-24 10:37:38 -0800439 data = None
Narayan Kamatha07bf042017-08-14 14:49:21 +0100440 if is_compressed:
441 # Recompress the file after it has been signed.
442 compressed = tempfile.NamedTemporaryFile()
Tao Bao0c28d2d2017-12-24 10:37:38 -0800443 with open(signed.name, "rb") as in_file, \
444 gzip.open(compressed.name, "wb") as out_file:
Narayan Kamatha07bf042017-08-14 14:49:21 +0100445 shutil.copyfileobj(in_file, out_file)
446
447 data = compressed.read()
448 compressed.close()
449 else:
450 data = signed.read()
451
Doug Zongkereef39442009-04-02 12:14:19 -0700452 unsigned.close()
453 signed.close()
454
455 return data
456
Tianjie5bd03952021-02-18 23:02:36 -0800457
Kelvin Zhang119f2792021-02-10 12:45:24 -0500458def IsBuildPropFile(filename):
459 return filename in (
460 "SYSTEM/etc/prop.default",
461 "BOOT/RAMDISK/prop.default",
462 "RECOVERY/RAMDISK/prop.default",
463
464 "VENDOR_BOOT/RAMDISK/default.prop",
465 "VENDOR_BOOT/RAMDISK/prop.default",
466
467 # ROOT/default.prop is a legacy path, but may still exist for upgrading
468 # devices that don't support `property_overrides_split_enabled`.
469 "ROOT/default.prop",
470
471 # RECOVERY/RAMDISK/default.prop is a legacy path, but will always exist
472 # as a symlink in the current code. So it's a no-op here. Keeping the
473 # path here for clarity.
474 "RECOVERY/RAMDISK/default.prop") or filename.endswith("build.prop")
Doug Zongkereef39442009-04-02 12:14:19 -0700475
Tianjie5bd03952021-02-18 23:02:36 -0800476
Doug Zongker412c02f2014-02-13 10:58:24 -0800477def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -0700478 apk_keys, apex_keys, key_passwords,
479 platform_api_level, codename_to_api_level_map,
Narayan Kamatha07bf042017-08-14 14:49:21 +0100480 compressed_extension):
Tao Bao93c2a012018-06-19 12:19:35 -0700481 # maxsize measures the maximum filename length, including the ones to be
482 # skipped.
Tao Bao0c28d2d2017-12-24 10:37:38 -0800483 maxsize = max(
484 [len(os.path.basename(i.filename)) for i in input_tf_zip.infolist()
Tao Bao93c2a012018-06-19 12:19:35 -0700485 if GetApkFileInfo(i.filename, compressed_extension, [])[0]])
Tao Baoa80ed222016-06-16 14:41:24 -0700486 system_root_image = misc_info.get("system_root_image") == "true"
Doug Zongker412c02f2014-02-13 10:58:24 -0800487
Doug Zongkereef39442009-04-02 12:14:19 -0700488 for info in input_tf_zip.infolist():
Tao Bao11f955c2018-06-19 12:19:35 -0700489 filename = info.filename
490 if filename.startswith("IMAGES/"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700491 continue
Doug Zongker3c84f562014-07-31 11:06:30 -0700492
Tao Bao04808502019-07-25 23:11:41 -0700493 # Skip OTA-specific images (e.g. split super images), which will be
494 # re-generated during signing.
Tao Bao33bf2682019-01-11 12:37:35 -0800495 if filename.startswith("OTA/") and filename.endswith(".img"):
496 continue
497
Tao Bao11f955c2018-06-19 12:19:35 -0700498 data = input_tf_zip.read(filename)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700499 out_info = copy.copy(info)
Tao Bao93c2a012018-06-19 12:19:35 -0700500 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
501 filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
502
503 if is_apk and should_be_skipped:
504 # Copy skipped APKs verbatim.
505 print(
506 "NOT signing: %s\n"
507 " (skipped due to matching prefix)" % (filename,))
508 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker412c02f2014-02-13 10:58:24 -0800509
Tao Baof2cffbd2015-07-22 12:33:18 -0700510 # Sign APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700511 elif is_apk:
Tao Bao11f955c2018-06-19 12:19:35 -0700512 name = os.path.basename(filename)
Narayan Kamatha07bf042017-08-14 14:49:21 +0100513 if is_compressed:
514 name = name[:-len(compressed_extension)]
515
Tao Baoaa7e9932019-03-15 09:37:01 -0700516 key = apk_keys[name]
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800517 if key not in common.SPECIAL_CERT_STRINGS:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800518 print(" signing: %-*s (%s)" % (maxsize, name, key))
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800519 signed_data = SignApk(data, key, key_passwords[key], platform_api_level,
Oleg Aravin8046cb02020-06-02 16:02:38 -0700520 codename_to_api_level_map, is_compressed, name)
Tao Bao2ed665a2015-04-01 11:21:55 -0700521 common.ZipWriteStr(output_tf_zip, out_info, signed_data)
Doug Zongkereef39442009-04-02 12:14:19 -0700522 else:
523 # an APK we're not supposed to sign.
Tao Bao93c2a012018-06-19 12:19:35 -0700524 print(
525 "NOT signing: %s\n"
526 " (skipped due to special cert string)" % (name,))
Tao Bao2ed665a2015-04-01 11:21:55 -0700527 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoa80ed222016-06-16 14:41:24 -0700528
Tianjie5bd03952021-02-18 23:02:36 -0800529 # Sign bundled APEX files on all partitions
530 elif filename.endswith(".apex"):
Tao Baoaa7e9932019-03-15 09:37:01 -0700531 name = os.path.basename(filename)
532 payload_key, container_key = apex_keys[name]
533
Tao Baoe1343992019-03-19 12:24:03 -0700534 # We've asserted not having a case with only one of them PRESIGNED.
535 if (payload_key not in common.SPECIAL_CERT_STRINGS and
536 container_key not in common.SPECIAL_CERT_STRINGS):
537 print(" signing: %-*s container (%s)" % (
538 maxsize, name, container_key))
539 print(" : %-*s payload (%s)" % (
540 maxsize, name, payload_key))
Tao Baoaa7e9932019-03-15 09:37:01 -0700541
Tao Baoe7354ba2019-05-09 16:54:15 -0700542 signed_apex = apex_utils.SignApex(
Tao Bao1ac886e2019-06-26 11:58:22 -0700543 misc_info['avb_avbtool'],
Tao Baoe1343992019-03-19 12:24:03 -0700544 data,
545 payload_key,
546 container_key,
Oleh Cherpake555ab12020-10-05 17:04:59 +0300547 key_passwords,
Tianjie Xu88a759d2020-01-23 10:47:54 -0800548 apk_keys,
Tao Baoe1343992019-03-19 12:24:03 -0700549 codename_to_api_level_map,
Tao Bao448004a2019-09-19 07:55:02 -0700550 no_hashtree=True,
551 signing_args=OPTIONS.avb_extra_args.get('apex'))
Tao Baoe1343992019-03-19 12:24:03 -0700552 common.ZipWrite(output_tf_zip, signed_apex, filename)
Tao Baoaa7e9932019-03-15 09:37:01 -0700553
Tao Baoe1343992019-03-19 12:24:03 -0700554 else:
555 print(
556 "NOT signing: %s\n"
557 " (skipped due to special cert string)" % (name,))
558 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoaa7e9932019-03-15 09:37:01 -0700559
Tao Baoa80ed222016-06-16 14:41:24 -0700560 # System properties.
Kelvin Zhang119f2792021-02-10 12:45:24 -0500561 elif IsBuildPropFile(filename):
Tao Bao11f955c2018-06-19 12:19:35 -0700562 print("Rewriting %s:" % (filename,))
Hung-ying Tyan7eb6a922017-05-01 21:56:26 +0800563 if stat.S_ISLNK(info.external_attr >> 16):
564 new_data = data
565 else:
Tao Baoa3705452019-06-24 15:33:41 -0700566 new_data = RewriteProps(data.decode())
Tao Bao2ed665a2015-04-01 11:21:55 -0700567 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700568
Tao Bao66472632017-12-04 17:16:36 -0800569 # Replace the certs in *mac_permissions.xml (there could be multiple, such
570 # as {system,vendor}/etc/selinux/{plat,nonplat}_mac_permissions.xml).
Tao Bao11f955c2018-06-19 12:19:35 -0700571 elif filename.endswith("mac_permissions.xml"):
572 print("Rewriting %s with new keys." % (filename,))
Tao Baoa3705452019-06-24 15:33:41 -0700573 new_data = ReplaceCerts(data.decode())
Tao Bao2ed665a2015-04-01 11:21:55 -0700574 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700575
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700576 # Ask add_img_to_target_files to rebuild the recovery patch if needed.
Tao Bao11f955c2018-06-19 12:19:35 -0700577 elif filename in ("SYSTEM/recovery-from-boot.p",
Robin Leeda427de2020-01-03 19:16:32 +0100578 "VENDOR/recovery-from-boot.p",
579
Tao Bao11f955c2018-06-19 12:19:35 -0700580 "SYSTEM/etc/recovery.img",
Robin Leeda427de2020-01-03 19:16:32 +0100581 "VENDOR/etc/recovery.img",
582
583 "SYSTEM/bin/install-recovery.sh",
584 "VENDOR/bin/install-recovery.sh"):
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700585 OPTIONS.rebuild_recovery = True
Tao Baoa80ed222016-06-16 14:41:24 -0700586
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700587 # Don't copy OTA certs if we're replacing them.
Tianjie Xu2df23d72019-10-15 18:06:25 -0700588 # Replacement of update-payload-key.pub.pem was removed in b/116660991.
Kelvin Zhang9f781ff2021-02-11 19:10:44 -0500589 elif OPTIONS.replace_ota_keys and filename.endswith("/otacerts.zip"):
Doug Zongker412c02f2014-02-13 10:58:24 -0800590 pass
Tao Baoa80ed222016-06-16 14:41:24 -0700591
Tao Bao46a59992017-06-05 11:55:16 -0700592 # Skip META/misc_info.txt since we will write back the new values later.
Tao Bao11f955c2018-06-19 12:19:35 -0700593 elif filename == "META/misc_info.txt":
Geremy Condraf19b3652014-07-29 17:54:54 -0700594 pass
Tao Bao8adcfd12016-06-17 17:01:22 -0700595
596 # Skip verity public key if we will replace it.
Michael Runge947894f2014-10-14 20:58:38 -0700597 elif (OPTIONS.replace_verity_public_key and
Tao Bao11f955c2018-06-19 12:19:35 -0700598 filename in ("BOOT/RAMDISK/verity_key",
599 "ROOT/verity_key")):
Geremy Condraf19b3652014-07-29 17:54:54 -0700600 pass
Bowgo Tsai2fe786a2020-02-21 17:48:18 +0800601 elif (OPTIONS.remove_avb_public_keys and
602 (filename.startswith("BOOT/RAMDISK/avb/") or
603 filename.startswith("BOOT/RAMDISK/first_stage_ramdisk/avb/"))):
Kelvin Zhang0876c412020-06-23 15:06:58 -0400604 matched_removal = False
605 for key_to_remove in OPTIONS.remove_avb_public_keys:
606 if filename.endswith(key_to_remove):
607 matched_removal = True
608 print("Removing AVB public key from ramdisk: %s" % filename)
609 break
610 if not matched_removal:
611 # Copy it verbatim if we don't want to remove it.
612 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoa80ed222016-06-16 14:41:24 -0700613
Tao Bao8adcfd12016-06-17 17:01:22 -0700614 # Skip verity keyid (for system_root_image use) if we will replace it.
Tao Bao11f955c2018-06-19 12:19:35 -0700615 elif OPTIONS.replace_verity_keyid and filename == "BOOT/cmdline":
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700616 pass
617
Tianjie Xu4f099002016-08-11 18:04:27 -0700618 # Skip the care_map as we will regenerate the system/vendor images.
Kelvin Zhang0876c412020-06-23 15:06:58 -0400619 elif filename in ["META/care_map.pb", "META/care_map.txt"]:
Tianjie Xu4f099002016-08-11 18:04:27 -0700620 pass
621
Kelvin Zhang5f0fcee2021-01-19 15:30:46 -0500622 # Skip apex_info.pb because we sign/modify apexes
623 elif filename == "META/apex_info.pb":
624 pass
625
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800626 # Updates system_other.avbpubkey in /product/etc/.
627 elif filename in (
628 "PRODUCT/etc/security/avb/system_other.avbpubkey",
629 "SYSTEM/product/etc/security/avb/system_other.avbpubkey"):
630 # Only update system_other's public key, if the corresponding signing
631 # key is specified via --avb_system_other_key.
632 signing_key = OPTIONS.avb_keys.get("system_other")
633 if signing_key:
Tao Bao1ac886e2019-06-26 11:58:22 -0700634 public_key = common.ExtractAvbPublicKey(
635 misc_info['avb_avbtool'], signing_key)
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800636 print(" Rewriting AVB public key of system_other in /product")
637 common.ZipWrite(output_tf_zip, public_key, filename)
638
Bowgo Tsai78369eb2019-04-23 12:28:44 +0800639 # Should NOT sign boot-debug.img.
640 elif filename in (
641 "BOOT/RAMDISK/force_debuggable",
Bowgo Tsai2fe786a2020-02-21 17:48:18 +0800642 "BOOT/RAMDISK/first_stage_ramdisk/force_debuggable"):
Bowgo Tsai78369eb2019-04-23 12:28:44 +0800643 raise common.ExternalError("debuggable boot.img cannot be signed")
644
Tao Baoa80ed222016-06-16 14:41:24 -0700645 # A non-APK file; copy it verbatim.
Doug Zongkereef39442009-04-02 12:14:19 -0700646 else:
Tao Bao2ed665a2015-04-01 11:21:55 -0700647 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700648
Doug Zongker412c02f2014-02-13 10:58:24 -0800649 if OPTIONS.replace_ota_keys:
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700650 ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info)
Doug Zongker412c02f2014-02-13 10:58:24 -0800651
Tao Bao46a59992017-06-05 11:55:16 -0700652 # Replace the keyid string in misc_info dict.
Tao Bao8adcfd12016-06-17 17:01:22 -0700653 if OPTIONS.replace_verity_private_key:
Tao Bao46a59992017-06-05 11:55:16 -0700654 ReplaceVerityPrivateKey(misc_info, OPTIONS.replace_verity_private_key[1])
Tao Bao8adcfd12016-06-17 17:01:22 -0700655
656 if OPTIONS.replace_verity_public_key:
Tao Baoc9981932019-09-16 12:10:43 -0700657 # Replace the one in root dir in system.img.
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700658 ReplaceVerityPublicKey(
Tao Baoc9981932019-09-16 12:10:43 -0700659 output_tf_zip, 'ROOT/verity_key', OPTIONS.replace_verity_public_key[1])
660
661 if not system_root_image:
662 # Additionally replace the copy in ramdisk if not using system-as-root.
663 ReplaceVerityPublicKey(
664 output_tf_zip,
665 'BOOT/RAMDISK/verity_key',
666 OPTIONS.replace_verity_public_key[1])
Tao Bao8adcfd12016-06-17 17:01:22 -0700667
668 # Replace the keyid string in BOOT/cmdline.
669 if OPTIONS.replace_verity_keyid:
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700670 ReplaceVerityKeyId(input_tf_zip, output_tf_zip,
671 OPTIONS.replace_verity_keyid[1])
Doug Zongker412c02f2014-02-13 10:58:24 -0800672
Tao Bao639118f2017-06-19 15:48:02 -0700673 # Replace the AVB signing keys, if any.
674 ReplaceAvbSigningKeys(misc_info)
675
Tao Bao19b02fe2019-10-09 00:04:28 -0700676 # Rewrite the props in AVB signing args.
677 if misc_info.get('avb_enable') == 'true':
678 RewriteAvbProps(misc_info)
679
Tao Bao46a59992017-06-05 11:55:16 -0700680 # Write back misc_info with the latest values.
681 ReplaceMiscInfoTxt(input_tf_zip, output_tf_zip, misc_info)
682
Doug Zongker8e931bf2009-04-06 15:21:45 -0700683
Robert Craig817c5742013-04-19 10:59:22 -0400684def ReplaceCerts(data):
Tao Bao66472632017-12-04 17:16:36 -0800685 """Replaces all the occurences of X.509 certs with the new ones.
Robert Craig817c5742013-04-19 10:59:22 -0400686
Tao Bao66472632017-12-04 17:16:36 -0800687 The mapping info is read from OPTIONS.key_map. Non-existent certificate will
688 be skipped. After the replacement, it additionally checks for duplicate
689 entries, which would otherwise fail the policy loading code in
690 frameworks/base/services/core/java/com/android/server/pm/SELinuxMMAC.java.
691
692 Args:
693 data: Input string that contains a set of X.509 certs.
694
695 Returns:
696 A string after the replacement.
697
698 Raises:
699 AssertionError: On finding duplicate entries.
700 """
Tao Baoa3705452019-06-24 15:33:41 -0700701 for old, new in OPTIONS.key_map.items():
Tao Bao66472632017-12-04 17:16:36 -0800702 if OPTIONS.verbose:
703 print(" Replacing %s.x509.pem with %s.x509.pem" % (old, new))
704
705 try:
706 with open(old + ".x509.pem") as old_fp:
707 old_cert16 = base64.b16encode(
Tao Baoa3705452019-06-24 15:33:41 -0700708 common.ParseCertificate(old_fp.read())).decode().lower()
Tao Bao66472632017-12-04 17:16:36 -0800709 with open(new + ".x509.pem") as new_fp:
710 new_cert16 = base64.b16encode(
Tao Baoa3705452019-06-24 15:33:41 -0700711 common.ParseCertificate(new_fp.read())).decode().lower()
Tao Bao66472632017-12-04 17:16:36 -0800712 except IOError as e:
713 if OPTIONS.verbose or e.errno != errno.ENOENT:
714 print(" Error accessing %s: %s.\nSkip replacing %s.x509.pem with "
715 "%s.x509.pem." % (e.filename, e.strerror, old, new))
716 continue
717
718 # Only match entire certs.
719 pattern = "\\b" + old_cert16 + "\\b"
720 (data, num) = re.subn(pattern, new_cert16, data, flags=re.IGNORECASE)
721
722 if OPTIONS.verbose:
723 print(" Replaced %d occurence(s) of %s.x509.pem with %s.x509.pem" % (
724 num, old, new))
725
726 # Verify that there're no duplicate entries after the replacement. Note that
727 # it's only checking entries with global seinfo at the moment (i.e. ignoring
728 # the ones with inner packages). (Bug: 69479366)
729 root = ElementTree.fromstring(data)
730 signatures = [signer.attrib['signature'] for signer in root.findall('signer')]
731 assert len(signatures) == len(set(signatures)), \
732 "Found duplicate entries after cert replacement: {}".format(data)
Robert Craig817c5742013-04-19 10:59:22 -0400733
734 return data
735
736
Doug Zongkerc09abc82010-01-11 13:09:15 -0800737def EditTags(tags):
Tao Baoa7054ee2017-12-08 14:42:16 -0800738 """Applies the edits to the tag string as specified in OPTIONS.tag_changes.
739
740 Args:
741 tags: The input string that contains comma-separated tags.
742
743 Returns:
744 The updated tags (comma-separated and sorted).
745 """
Doug Zongkerc09abc82010-01-11 13:09:15 -0800746 tags = set(tags.split(","))
747 for ch in OPTIONS.tag_changes:
748 if ch[0] == "-":
749 tags.discard(ch[1:])
750 elif ch[0] == "+":
751 tags.add(ch[1:])
752 return ",".join(sorted(tags))
753
754
Tao Baoa7054ee2017-12-08 14:42:16 -0800755def RewriteProps(data):
756 """Rewrites the system properties in the given string.
757
758 Each property is expected in 'key=value' format. The properties that contain
759 build tags (i.e. test-keys, dev-keys) will be updated accordingly by calling
760 EditTags().
761
762 Args:
763 data: Input string, separated by newlines.
764
765 Returns:
766 The string with modified properties.
767 """
Doug Zongker17aa9442009-04-17 10:15:58 -0700768 output = []
769 for line in data.split("\n"):
770 line = line.strip()
771 original_line = line
Michael Rungedc2661a2014-06-03 14:43:11 -0700772 if line and line[0] != '#' and "=" in line:
Doug Zongker17aa9442009-04-17 10:15:58 -0700773 key, value = line.split("=", 1)
Magnus Strandh234f4b42019-05-01 23:09:30 +0200774 if (key.startswith("ro.") and
775 key.endswith((".build.fingerprint", ".build.thumbprint"))):
Doug Zongkerc09abc82010-01-11 13:09:15 -0800776 pieces = value.split("/")
777 pieces[-1] = EditTags(pieces[-1])
778 value = "/".join(pieces)
Tao Baocb7ff772015-09-11 15:27:56 -0700779 elif key == "ro.bootimage.build.fingerprint":
780 pieces = value.split("/")
781 pieces[-1] = EditTags(pieces[-1])
782 value = "/".join(pieces)
Doug Zongker17aa9442009-04-17 10:15:58 -0700783 elif key == "ro.build.description":
Doug Zongkerc09abc82010-01-11 13:09:15 -0800784 pieces = value.split(" ")
Doug Zongker17aa9442009-04-17 10:15:58 -0700785 assert len(pieces) == 5
Doug Zongkerc09abc82010-01-11 13:09:15 -0800786 pieces[-1] = EditTags(pieces[-1])
787 value = " ".join(pieces)
Magnus Strandh234f4b42019-05-01 23:09:30 +0200788 elif key.startswith("ro.") and key.endswith(".build.tags"):
Doug Zongkerc09abc82010-01-11 13:09:15 -0800789 value = EditTags(value)
Doug Zongkera8608a72013-07-23 11:51:04 -0700790 elif key == "ro.build.display.id":
791 # change, eg, "JWR66N dev-keys" to "JWR66N"
792 value = value.split()
Michael Rungedc2661a2014-06-03 14:43:11 -0700793 if len(value) > 1 and value[-1].endswith("-keys"):
Andrew Boie73d5abb2013-12-11 12:42:03 -0800794 value.pop()
795 value = " ".join(value)
Doug Zongkerc09abc82010-01-11 13:09:15 -0800796 line = key + "=" + value
Doug Zongker17aa9442009-04-17 10:15:58 -0700797 if line != original_line:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800798 print(" replace: ", original_line)
799 print(" with: ", line)
Doug Zongker17aa9442009-04-17 10:15:58 -0700800 output.append(line)
801 return "\n".join(output) + "\n"
802
803
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700804def WriteOtacerts(output_zip, filename, keys):
805 """Constructs a zipfile from given keys; and writes it to output_zip.
806
807 Args:
808 output_zip: The output target_files zip.
809 filename: The archive name in the output zip.
810 keys: A list of public keys to use during OTA package verification.
811 """
Tao Baobb733882019-07-24 23:31:19 -0700812 temp_file = io.BytesIO()
Kelvin Zhang928c2342020-09-22 16:15:57 -0400813 certs_zip = zipfile.ZipFile(temp_file, "w", allowZip64=True)
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700814 for k in keys:
815 common.ZipWrite(certs_zip, k)
816 common.ZipClose(certs_zip)
817 common.ZipWriteStr(output_zip, filename, temp_file.getvalue())
818
819
Doug Zongker831840e2011-09-22 10:28:04 -0700820def ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info):
Doug Zongker8e931bf2009-04-06 15:21:45 -0700821 try:
822 keylist = input_tf_zip.read("META/otakeys.txt").split()
823 except KeyError:
T.R. Fullharta28acc62013-03-18 10:31:26 -0700824 raise common.ExternalError("can't read META/otakeys.txt from input")
Doug Zongker8e931bf2009-04-06 15:21:45 -0700825
Tao Baof718f902017-11-09 10:10:10 -0800826 extra_recovery_keys = misc_info.get("extra_recovery_keys")
Doug Zongkere121d6a2011-02-01 14:13:52 -0800827 if extra_recovery_keys:
828 extra_recovery_keys = [OPTIONS.key_map.get(k, k) + ".x509.pem"
829 for k in extra_recovery_keys.split()]
830 if extra_recovery_keys:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800831 print("extra recovery-only key(s): " + ", ".join(extra_recovery_keys))
Doug Zongkere121d6a2011-02-01 14:13:52 -0800832 else:
833 extra_recovery_keys = []
834
Doug Zongker8e931bf2009-04-06 15:21:45 -0700835 mapped_keys = []
836 for k in keylist:
837 m = re.match(r"^(.*)\.x509\.pem$", k)
838 if not m:
Doug Zongker412c02f2014-02-13 10:58:24 -0800839 raise common.ExternalError(
840 "can't parse \"%s\" from META/otakeys.txt" % (k,))
Doug Zongker8e931bf2009-04-06 15:21:45 -0700841 k = m.group(1)
842 mapped_keys.append(OPTIONS.key_map.get(k, k) + ".x509.pem")
843
Doug Zongkere05628c2009-08-20 17:38:42 -0700844 if mapped_keys:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800845 print("using:\n ", "\n ".join(mapped_keys))
846 print("for OTA package verification")
Doug Zongkere05628c2009-08-20 17:38:42 -0700847 else:
Doug Zongker831840e2011-09-22 10:28:04 -0700848 devkey = misc_info.get("default_system_dev_certificate",
Dan Willemsen0ab1be62019-04-09 21:35:37 -0700849 "build/make/target/product/security/testkey")
Tao Baof718f902017-11-09 10:10:10 -0800850 mapped_devkey = OPTIONS.key_map.get(devkey, devkey)
851 if mapped_devkey != devkey:
852 misc_info["default_system_dev_certificate"] = mapped_devkey
853 mapped_keys.append(mapped_devkey + ".x509.pem")
Tao Baoa80ed222016-06-16 14:41:24 -0700854 print("META/otakeys.txt has no keys; using %s for OTA package"
855 " verification." % (mapped_keys[0],))
Doug Zongker8e931bf2009-04-06 15:21:45 -0700856
Kelvin Zhang9f781ff2021-02-11 19:10:44 -0500857 otacerts = [info
858 for info in input_tf_zip.infolist()
859 if info.filename.endswith("/otacerts.zip")]
860 for info in otacerts:
861 print("Rewriting OTA key:", info.filename, mapped_keys)
862 WriteOtacerts(output_tf_zip, info.filename, mapped_keys)
Doug Zongkereef39442009-04-02 12:14:19 -0700863
Tao Baoa80ed222016-06-16 14:41:24 -0700864
Tao Bao0c28d2d2017-12-24 10:37:38 -0800865def ReplaceVerityPublicKey(output_zip, filename, key_path):
866 """Replaces the verity public key at the given path in the given zip.
867
868 Args:
869 output_zip: The output target_files zip.
870 filename: The archive name in the output zip.
871 key_path: The path to the public key.
872 """
873 print("Replacing verity public key with %s" % (key_path,))
874 common.ZipWrite(output_zip, key_path, arcname=filename)
Geremy Condraf19b3652014-07-29 17:54:54 -0700875
Tao Bao8adcfd12016-06-17 17:01:22 -0700876
Tao Bao46a59992017-06-05 11:55:16 -0700877def ReplaceVerityPrivateKey(misc_info, key_path):
Tao Bao0c28d2d2017-12-24 10:37:38 -0800878 """Replaces the verity private key in misc_info dict.
879
880 Args:
881 misc_info: The info dict.
882 key_path: The path to the private key in PKCS#8 format.
883 """
884 print("Replacing verity private key with %s" % (key_path,))
Andrew Boied083f0b2014-09-15 16:01:07 -0700885 misc_info["verity_key"] = key_path
Doug Zongkereef39442009-04-02 12:14:19 -0700886
Tao Bao8adcfd12016-06-17 17:01:22 -0700887
Tao Baoe838d142017-12-23 23:44:48 -0800888def ReplaceVerityKeyId(input_zip, output_zip, key_path):
889 """Replaces the veritykeyid parameter in BOOT/cmdline.
890
891 Args:
892 input_zip: The input target_files zip, which should be already open.
893 output_zip: The output target_files zip, which should be already open and
894 writable.
895 key_path: The path to the PEM encoded X.509 certificate.
896 """
Tao Baoa3705452019-06-24 15:33:41 -0700897 in_cmdline = input_zip.read("BOOT/cmdline").decode()
Tao Baoe838d142017-12-23 23:44:48 -0800898 # Copy in_cmdline to output_zip if veritykeyid is not present.
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700899 if "veritykeyid" not in in_cmdline:
Tao Baoe838d142017-12-23 23:44:48 -0800900 common.ZipWriteStr(output_zip, "BOOT/cmdline", in_cmdline)
901 return
902
Tao Bao0c28d2d2017-12-24 10:37:38 -0800903 out_buffer = []
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700904 for param in in_cmdline.split():
Tao Baoe838d142017-12-23 23:44:48 -0800905 if "veritykeyid" not in param:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800906 out_buffer.append(param)
Tao Baoe838d142017-12-23 23:44:48 -0800907 continue
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700908
Tao Baoe838d142017-12-23 23:44:48 -0800909 # Extract keyid using openssl command.
910 p = common.Run(["openssl", "x509", "-in", key_path, "-text"],
Tao Baode1d4792018-02-20 10:05:46 -0800911 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
Tao Baoe838d142017-12-23 23:44:48 -0800912 keyid, stderr = p.communicate()
913 assert p.returncode == 0, "Failed to dump certificate: {}".format(stderr)
914 keyid = re.search(
915 r'keyid:([0-9a-fA-F:]*)', keyid).group(1).replace(':', '').lower()
916 print("Replacing verity keyid with {}".format(keyid))
917 out_buffer.append("veritykeyid=id:%s" % (keyid,))
918
919 out_cmdline = ' '.join(out_buffer).strip() + '\n'
920 common.ZipWriteStr(output_zip, "BOOT/cmdline", out_cmdline)
Tao Bao46a59992017-06-05 11:55:16 -0700921
922
923def ReplaceMiscInfoTxt(input_zip, output_zip, misc_info):
924 """Replaces META/misc_info.txt.
925
926 Only writes back the ones in the original META/misc_info.txt. Because the
927 current in-memory dict contains additional items computed at runtime.
928 """
929 misc_info_old = common.LoadDictionaryFromLines(
Tao Baoa3705452019-06-24 15:33:41 -0700930 input_zip.read('META/misc_info.txt').decode().split('\n'))
Tao Bao46a59992017-06-05 11:55:16 -0700931 items = []
932 for key in sorted(misc_info):
933 if key in misc_info_old:
934 items.append('%s=%s' % (key, misc_info[key]))
935 common.ZipWriteStr(output_zip, "META/misc_info.txt", '\n'.join(items))
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700936
Tao Bao8adcfd12016-06-17 17:01:22 -0700937
Tao Bao639118f2017-06-19 15:48:02 -0700938def ReplaceAvbSigningKeys(misc_info):
939 """Replaces the AVB signing keys."""
940
Tao Bao639118f2017-06-19 15:48:02 -0700941 def ReplaceAvbPartitionSigningKey(partition):
942 key = OPTIONS.avb_keys.get(partition)
943 if not key:
944 return
945
946 algorithm = OPTIONS.avb_algorithms.get(partition)
947 assert algorithm, 'Missing AVB signing algorithm for %s' % (partition,)
948
Tao Bao0c28d2d2017-12-24 10:37:38 -0800949 print('Replacing AVB signing key for %s with "%s" (%s)' % (
950 partition, key, algorithm))
Tao Bao639118f2017-06-19 15:48:02 -0700951 misc_info['avb_' + partition + '_algorithm'] = algorithm
952 misc_info['avb_' + partition + '_key_path'] = key
953
954 extra_args = OPTIONS.avb_extra_args.get(partition)
955 if extra_args:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800956 print('Setting extra AVB signing args for %s to "%s"' % (
957 partition, extra_args))
Kelvin Zhang0876c412020-06-23 15:06:58 -0400958 args_key = AVB_FOOTER_ARGS_BY_PARTITION.get(
959 partition,
960 # custom partition
961 "avb_{}_add_hashtree_footer_args".format(partition))
Tao Bao639118f2017-06-19 15:48:02 -0700962 misc_info[args_key] = (misc_info.get(args_key, '') + ' ' + extra_args)
963
964 for partition in AVB_FOOTER_ARGS_BY_PARTITION:
965 ReplaceAvbPartitionSigningKey(partition)
966
Hongguang Chenf23364d2020-04-27 18:36:36 -0700967 for custom_partition in misc_info.get(
968 "avb_custom_images_partition_list", "").strip().split():
969 ReplaceAvbPartitionSigningKey(custom_partition)
970
Tao Bao639118f2017-06-19 15:48:02 -0700971
Tao Bao19b02fe2019-10-09 00:04:28 -0700972def RewriteAvbProps(misc_info):
973 """Rewrites the props in AVB signing args."""
974 for partition, args_key in AVB_FOOTER_ARGS_BY_PARTITION.items():
975 args = misc_info.get(args_key)
976 if not args:
977 continue
978
979 tokens = []
980 changed = False
981 for token in args.split(' '):
982 fingerprint_key = 'com.android.build.{}.fingerprint'.format(partition)
983 if not token.startswith(fingerprint_key):
984 tokens.append(token)
985 continue
986 prefix, tag = token.rsplit('/', 1)
987 tokens.append('{}/{}'.format(prefix, EditTags(tag)))
988 changed = True
989
990 if changed:
991 result = ' '.join(tokens)
992 print('Rewriting AVB prop for {}:\n'.format(partition))
993 print(' replace: {}'.format(args))
994 print(' with: {}'.format(result))
995 misc_info[args_key] = result
996
997
Doug Zongker831840e2011-09-22 10:28:04 -0700998def BuildKeyMap(misc_info, key_mapping_options):
999 for s, d in key_mapping_options:
1000 if s is None: # -d option
1001 devkey = misc_info.get("default_system_dev_certificate",
Dan Willemsen0ab1be62019-04-09 21:35:37 -07001002 "build/make/target/product/security/testkey")
Doug Zongker831840e2011-09-22 10:28:04 -07001003 devkeydir = os.path.dirname(devkey)
1004
1005 OPTIONS.key_map.update({
1006 devkeydir + "/testkey": d + "/releasekey",
1007 devkeydir + "/devkey": d + "/releasekey",
1008 devkeydir + "/media": d + "/media",
1009 devkeydir + "/shared": d + "/shared",
1010 devkeydir + "/platform": d + "/platform",
Oleh Cherpak982e6082019-12-10 12:58:54 +02001011 devkeydir + "/networkstack": d + "/networkstack",
Doug Zongker831840e2011-09-22 10:28:04 -07001012 })
1013 else:
1014 OPTIONS.key_map[s] = d
1015
1016
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001017def GetApiLevelAndCodename(input_tf_zip):
Tao Baoa3705452019-06-24 15:33:41 -07001018 data = input_tf_zip.read("SYSTEM/build.prop").decode()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001019 api_level = None
1020 codename = None
1021 for line in data.split("\n"):
1022 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001023 if line and line[0] != '#' and "=" in line:
1024 key, value = line.split("=", 1)
1025 key = key.strip()
1026 if key == "ro.build.version.sdk":
1027 api_level = int(value.strip())
1028 elif key == "ro.build.version.codename":
1029 codename = value.strip()
1030
1031 if api_level is None:
1032 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
1033 if codename is None:
1034 raise ValueError("No ro.build.version.codename in SYSTEM/build.prop")
1035
1036 return (api_level, codename)
1037
1038
1039def GetCodenameToApiLevelMap(input_tf_zip):
Tao Baoa3705452019-06-24 15:33:41 -07001040 data = input_tf_zip.read("SYSTEM/build.prop").decode()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001041 api_level = None
1042 codenames = None
1043 for line in data.split("\n"):
1044 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001045 if line and line[0] != '#' and "=" in line:
1046 key, value = line.split("=", 1)
1047 key = key.strip()
1048 if key == "ro.build.version.sdk":
1049 api_level = int(value.strip())
1050 elif key == "ro.build.version.all_codenames":
1051 codenames = value.strip().split(",")
1052
1053 if api_level is None:
1054 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
1055 if codenames is None:
1056 raise ValueError("No ro.build.version.all_codenames in SYSTEM/build.prop")
1057
Tao Baoa3705452019-06-24 15:33:41 -07001058 result = {}
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001059 for codename in codenames:
1060 codename = codename.strip()
Tao Baobadceb22019-03-15 09:33:43 -07001061 if codename:
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001062 result[codename] = api_level
1063 return result
1064
1065
Tao Baoaa7e9932019-03-15 09:37:01 -07001066def ReadApexKeysInfo(tf_zip):
1067 """Parses the APEX keys info from a given target-files zip.
1068
1069 Given a target-files ZipFile, parses the META/apexkeys.txt entry and returns a
1070 dict that contains the mapping from APEX names (e.g. com.android.tzdata) to a
1071 tuple of (payload_key, container_key).
1072
1073 Args:
1074 tf_zip: The input target_files ZipFile (already open).
1075
1076 Returns:
1077 (payload_key, container_key): payload_key contains the path to the payload
1078 signing key; container_key contains the path to the container signing
1079 key.
1080 """
1081 keys = {}
Tao Baoa3705452019-06-24 15:33:41 -07001082 for line in tf_zip.read('META/apexkeys.txt').decode().split('\n'):
Tao Baoaa7e9932019-03-15 09:37:01 -07001083 line = line.strip()
1084 if not line:
1085 continue
1086 matches = re.match(
1087 r'^name="(?P<NAME>.*)"\s+'
1088 r'public_key="(?P<PAYLOAD_PUBLIC_KEY>.*)"\s+'
1089 r'private_key="(?P<PAYLOAD_PRIVATE_KEY>.*)"\s+'
1090 r'container_certificate="(?P<CONTAINER_CERT>.*)"\s+'
Bill Peckham5c7b0342020-04-03 15:36:23 -07001091 r'container_private_key="(?P<CONTAINER_PRIVATE_KEY>.*?)"'
1092 r'(\s+partition="(?P<PARTITION>.*?)")?$',
Tao Baoaa7e9932019-03-15 09:37:01 -07001093 line)
1094 if not matches:
1095 continue
1096
1097 name = matches.group('NAME')
Tao Baoaa7e9932019-03-15 09:37:01 -07001098 payload_private_key = matches.group("PAYLOAD_PRIVATE_KEY")
1099
1100 def CompareKeys(pubkey, pubkey_suffix, privkey, privkey_suffix):
1101 pubkey_suffix_len = len(pubkey_suffix)
1102 privkey_suffix_len = len(privkey_suffix)
1103 return (pubkey.endswith(pubkey_suffix) and
1104 privkey.endswith(privkey_suffix) and
1105 pubkey[:-pubkey_suffix_len] == privkey[:-privkey_suffix_len])
1106
Ivan Lozanob021b2a2020-07-28 09:31:06 -04001107 # Check the container key names, as we'll carry them without the
Tao Bao6d9e3da2019-03-26 12:59:25 -07001108 # extensions. This doesn't apply to payload keys though, which we will use
1109 # full names only.
Tao Baoaa7e9932019-03-15 09:37:01 -07001110 container_cert = matches.group("CONTAINER_CERT")
1111 container_private_key = matches.group("CONTAINER_PRIVATE_KEY")
Tao Baof454c3a2019-04-24 23:53:42 -07001112 if container_cert == 'PRESIGNED' and container_private_key == 'PRESIGNED':
1113 container_key = 'PRESIGNED'
1114 elif CompareKeys(
Tao Baoaa7e9932019-03-15 09:37:01 -07001115 container_cert, OPTIONS.public_key_suffix,
1116 container_private_key, OPTIONS.private_key_suffix):
Tao Baof454c3a2019-04-24 23:53:42 -07001117 container_key = container_cert[:-len(OPTIONS.public_key_suffix)]
1118 else:
Tao Baoaa7e9932019-03-15 09:37:01 -07001119 raise ValueError("Failed to parse container keys: \n{}".format(line))
1120
Tao Baof454c3a2019-04-24 23:53:42 -07001121 keys[name] = (payload_private_key, container_key)
Tao Baoaa7e9932019-03-15 09:37:01 -07001122
1123 return keys
1124
1125
Doug Zongkereef39442009-04-02 12:14:19 -07001126def main(argv):
1127
Doug Zongker831840e2011-09-22 10:28:04 -07001128 key_mapping_options = []
1129
Doug Zongkereef39442009-04-02 12:14:19 -07001130 def option_handler(o, a):
Doug Zongker05d3dea2009-06-22 11:32:31 -07001131 if o in ("-e", "--extra_apks"):
Doug Zongkereef39442009-04-02 12:14:19 -07001132 names, key = a.split("=")
1133 names = names.split(",")
1134 for n in names:
1135 OPTIONS.extra_apks[n] = key
Tao Baoaa7e9932019-03-15 09:37:01 -07001136 elif o == "--extra_apex_payload_key":
1137 apex_name, key = a.split("=")
1138 OPTIONS.extra_apex_payload_keys[apex_name] = key
Tao Bao93c2a012018-06-19 12:19:35 -07001139 elif o == "--skip_apks_with_path_prefix":
Tianjiea85bdf02020-07-29 11:56:19 -07001140 # Check the prefix, which must be in all upper case.
Tao Bao93c2a012018-06-19 12:19:35 -07001141 prefix = a.split('/')[0]
1142 if not prefix or prefix != prefix.upper():
1143 raise ValueError("Invalid path prefix '%s'" % (a,))
1144 OPTIONS.skip_apks_with_path_prefix.add(a)
Doug Zongkereef39442009-04-02 12:14:19 -07001145 elif o in ("-d", "--default_key_mappings"):
Doug Zongker831840e2011-09-22 10:28:04 -07001146 key_mapping_options.append((None, a))
Doug Zongkereef39442009-04-02 12:14:19 -07001147 elif o in ("-k", "--key_mapping"):
Doug Zongker831840e2011-09-22 10:28:04 -07001148 key_mapping_options.append(a.split("=", 1))
Doug Zongker8e931bf2009-04-06 15:21:45 -07001149 elif o in ("-o", "--replace_ota_keys"):
1150 OPTIONS.replace_ota_keys = True
Doug Zongkerae877012009-04-21 10:04:51 -07001151 elif o in ("-t", "--tag_changes"):
1152 new = []
1153 for i in a.split(","):
1154 i = i.strip()
1155 if not i or i[0] not in "-+":
1156 raise ValueError("Bad tag change '%s'" % (i,))
1157 new.append(i[0] + i[1:].strip())
1158 OPTIONS.tag_changes = tuple(new)
Geremy Condraf19b3652014-07-29 17:54:54 -07001159 elif o == "--replace_verity_public_key":
1160 OPTIONS.replace_verity_public_key = (True, a)
1161 elif o == "--replace_verity_private_key":
1162 OPTIONS.replace_verity_private_key = (True, a)
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001163 elif o == "--replace_verity_keyid":
1164 OPTIONS.replace_verity_keyid = (True, a)
Bowgo Tsai2fe786a2020-02-21 17:48:18 +08001165 elif o == "--remove_avb_public_keys":
1166 OPTIONS.remove_avb_public_keys = a.split(",")
Tao Bao639118f2017-06-19 15:48:02 -07001167 elif o == "--avb_vbmeta_key":
1168 OPTIONS.avb_keys['vbmeta'] = a
1169 elif o == "--avb_vbmeta_algorithm":
1170 OPTIONS.avb_algorithms['vbmeta'] = a
1171 elif o == "--avb_vbmeta_extra_args":
1172 OPTIONS.avb_extra_args['vbmeta'] = a
1173 elif o == "--avb_boot_key":
1174 OPTIONS.avb_keys['boot'] = a
1175 elif o == "--avb_boot_algorithm":
1176 OPTIONS.avb_algorithms['boot'] = a
1177 elif o == "--avb_boot_extra_args":
1178 OPTIONS.avb_extra_args['boot'] = a
1179 elif o == "--avb_dtbo_key":
1180 OPTIONS.avb_keys['dtbo'] = a
1181 elif o == "--avb_dtbo_algorithm":
1182 OPTIONS.avb_algorithms['dtbo'] = a
1183 elif o == "--avb_dtbo_extra_args":
1184 OPTIONS.avb_extra_args['dtbo'] = a
1185 elif o == "--avb_system_key":
1186 OPTIONS.avb_keys['system'] = a
1187 elif o == "--avb_system_algorithm":
1188 OPTIONS.avb_algorithms['system'] = a
1189 elif o == "--avb_system_extra_args":
1190 OPTIONS.avb_extra_args['system'] = a
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001191 elif o == "--avb_system_other_key":
1192 OPTIONS.avb_keys['system_other'] = a
1193 elif o == "--avb_system_other_algorithm":
1194 OPTIONS.avb_algorithms['system_other'] = a
1195 elif o == "--avb_system_other_extra_args":
1196 OPTIONS.avb_extra_args['system_other'] = a
Tao Bao639118f2017-06-19 15:48:02 -07001197 elif o == "--avb_vendor_key":
1198 OPTIONS.avb_keys['vendor'] = a
1199 elif o == "--avb_vendor_algorithm":
1200 OPTIONS.avb_algorithms['vendor'] = a
1201 elif o == "--avb_vendor_extra_args":
1202 OPTIONS.avb_extra_args['vendor'] = a
Tao Baod6085d62019-05-06 12:55:42 -07001203 elif o == "--avb_vbmeta_system_key":
1204 OPTIONS.avb_keys['vbmeta_system'] = a
1205 elif o == "--avb_vbmeta_system_algorithm":
1206 OPTIONS.avb_algorithms['vbmeta_system'] = a
1207 elif o == "--avb_vbmeta_system_extra_args":
1208 OPTIONS.avb_extra_args['vbmeta_system'] = a
1209 elif o == "--avb_vbmeta_vendor_key":
1210 OPTIONS.avb_keys['vbmeta_vendor'] = a
1211 elif o == "--avb_vbmeta_vendor_algorithm":
1212 OPTIONS.avb_algorithms['vbmeta_vendor'] = a
1213 elif o == "--avb_vbmeta_vendor_extra_args":
1214 OPTIONS.avb_extra_args['vbmeta_vendor'] = a
Tao Baoaa7e9932019-03-15 09:37:01 -07001215 elif o == "--avb_apex_extra_args":
1216 OPTIONS.avb_extra_args['apex'] = a
Hongguang Chenf23364d2020-04-27 18:36:36 -07001217 elif o == "--avb_extra_custom_image_key":
1218 partition, key = a.split("=")
1219 OPTIONS.avb_keys[partition] = key
1220 elif o == "--avb_extra_custom_image_algorithm":
1221 partition, algorithm = a.split("=")
1222 OPTIONS.avb_algorithms[partition] = algorithm
1223 elif o == "--avb_extra_custom_image_extra_args":
Hongguang Chen883eecb2020-05-23 22:20:19 -07001224 # Setting the maxsplit parameter to one, which will return a list with
1225 # two elements. e.g., the second '=' should not be splitted for
1226 # 'oem=--signing_helper_with_files=/tmp/avbsigner.sh'.
1227 partition, extra_args = a.split("=", 1)
Hongguang Chenf23364d2020-04-27 18:36:36 -07001228 OPTIONS.avb_extra_args[partition] = extra_args
Doug Zongkereef39442009-04-02 12:14:19 -07001229 else:
1230 return False
1231 return True
1232
Tao Bao639118f2017-06-19 15:48:02 -07001233 args = common.ParseOptions(
1234 argv, __doc__,
1235 extra_opts="e:d:k:ot:",
1236 extra_long_opts=[
Tao Bao0c28d2d2017-12-24 10:37:38 -08001237 "extra_apks=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001238 "extra_apex_payload_key=",
Tao Bao93c2a012018-06-19 12:19:35 -07001239 "skip_apks_with_path_prefix=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001240 "default_key_mappings=",
1241 "key_mapping=",
1242 "replace_ota_keys",
1243 "tag_changes=",
1244 "replace_verity_public_key=",
1245 "replace_verity_private_key=",
1246 "replace_verity_keyid=",
Bowgo Tsai2fe786a2020-02-21 17:48:18 +08001247 "remove_avb_public_keys=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001248 "avb_apex_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001249 "avb_vbmeta_algorithm=",
1250 "avb_vbmeta_key=",
1251 "avb_vbmeta_extra_args=",
1252 "avb_boot_algorithm=",
1253 "avb_boot_key=",
1254 "avb_boot_extra_args=",
1255 "avb_dtbo_algorithm=",
1256 "avb_dtbo_key=",
1257 "avb_dtbo_extra_args=",
1258 "avb_system_algorithm=",
1259 "avb_system_key=",
1260 "avb_system_extra_args=",
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001261 "avb_system_other_algorithm=",
1262 "avb_system_other_key=",
1263 "avb_system_other_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001264 "avb_vendor_algorithm=",
1265 "avb_vendor_key=",
1266 "avb_vendor_extra_args=",
Tao Baod6085d62019-05-06 12:55:42 -07001267 "avb_vbmeta_system_algorithm=",
1268 "avb_vbmeta_system_key=",
1269 "avb_vbmeta_system_extra_args=",
1270 "avb_vbmeta_vendor_algorithm=",
1271 "avb_vbmeta_vendor_key=",
1272 "avb_vbmeta_vendor_extra_args=",
Hongguang Chenf23364d2020-04-27 18:36:36 -07001273 "avb_extra_custom_image_key=",
1274 "avb_extra_custom_image_algorithm=",
1275 "avb_extra_custom_image_extra_args=",
Tao Bao639118f2017-06-19 15:48:02 -07001276 ],
1277 extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001278
1279 if len(args) != 2:
1280 common.Usage(__doc__)
1281 sys.exit(1)
1282
Tao Baobadceb22019-03-15 09:33:43 -07001283 common.InitLogging()
1284
Kelvin Zhang928c2342020-09-22 16:15:57 -04001285 input_zip = zipfile.ZipFile(args[0], "r", allowZip64=True)
Tao Bao2b8f4892017-06-13 12:54:58 -07001286 output_zip = zipfile.ZipFile(args[1], "w",
1287 compression=zipfile.ZIP_DEFLATED,
1288 allowZip64=True)
Doug Zongkereef39442009-04-02 12:14:19 -07001289
Doug Zongker831840e2011-09-22 10:28:04 -07001290 misc_info = common.LoadInfoDict(input_zip)
1291
1292 BuildKeyMap(misc_info, key_mapping_options)
1293
Tao Baoaa7e9932019-03-15 09:37:01 -07001294 apk_keys_info, compressed_extension = common.ReadApkCerts(input_zip)
1295 apk_keys = GetApkCerts(apk_keys_info)
Doug Zongkereb338ef2009-05-20 16:50:49 -07001296
Tao Baoaa7e9932019-03-15 09:37:01 -07001297 apex_keys_info = ReadApexKeysInfo(input_zip)
1298 apex_keys = GetApexKeys(apex_keys_info, apk_keys)
1299
Tianjie Xu88a759d2020-01-23 10:47:54 -08001300 # TODO(xunchang) check for the apks inside the apex files, and abort early if
1301 # the keys are not available.
Tao Baoaa7e9932019-03-15 09:37:01 -07001302 CheckApkAndApexKeysAvailable(
1303 input_zip,
1304 set(apk_keys.keys()) | set(apex_keys.keys()),
Tao Baoe1343992019-03-19 12:24:03 -07001305 compressed_extension,
1306 apex_keys)
Tao Baoaa7e9932019-03-15 09:37:01 -07001307
1308 key_passwords = common.GetKeyPasswords(
1309 set(apk_keys.values()) | set(itertools.chain(*apex_keys.values())))
Tao Bao9aa4b9b2016-09-29 17:53:56 -07001310 platform_api_level, _ = GetApiLevelAndCodename(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001311 codename_to_api_level_map = GetCodenameToApiLevelMap(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001312
Doug Zongker412c02f2014-02-13 10:58:24 -08001313 ProcessTargetFiles(input_zip, output_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -07001314 apk_keys, apex_keys, key_passwords,
1315 platform_api_level, codename_to_api_level_map,
Narayan Kamatha07bf042017-08-14 14:49:21 +01001316 compressed_extension)
Doug Zongker8e931bf2009-04-06 15:21:45 -07001317
Tao Bao2ed665a2015-04-01 11:21:55 -07001318 common.ZipClose(input_zip)
1319 common.ZipClose(output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001320
Tianjie Xub48589a2016-08-03 19:21:52 -07001321 # Skip building userdata.img and cache.img when signing the target files.
Tianjie Xu616fbeb2017-05-23 14:51:02 -07001322 new_args = ["--is_signing"]
1323 # add_img_to_target_files builds the system image from scratch, so the
1324 # recovery patch is guaranteed to be regenerated there.
1325 if OPTIONS.rebuild_recovery:
1326 new_args.append("--rebuild_recovery")
1327 new_args.append(args[1])
Tianjie Xub48589a2016-08-03 19:21:52 -07001328 add_img_to_target_files.main(new_args)
Doug Zongker3c84f562014-07-31 11:06:30 -07001329
Tao Bao0c28d2d2017-12-24 10:37:38 -08001330 print("done.")
Doug Zongkereef39442009-04-02 12:14:19 -07001331
1332
1333if __name__ == '__main__':
1334 try:
1335 main(sys.argv[1:])
Tao Bao0c28d2d2017-12-24 10:37:38 -08001336 except common.ExternalError as e:
1337 print("\n ERROR: %s\n" % (e,))
Doug Zongkereef39442009-04-02 12:14:19 -07001338 sys.exit(1)
Tao Bao639118f2017-06-19 15:48:02 -07001339 finally:
1340 common.Cleanup()