blob: 70f4a04fc3aec6ec06b3909a4209dac085df865f [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 = {
181 'boot' : 'avb_boot_add_hash_footer_args',
182 'dtbo' : 'avb_dtbo_add_hash_footer_args',
183 'recovery' : 'avb_recovery_add_hash_footer_args',
184 'system' : 'avb_system_add_hashtree_footer_args',
185 'system_other' : 'avb_system_other_add_hashtree_footer_args',
186 'vendor' : 'avb_vendor_add_hashtree_footer_args',
187 'vendor_boot' : 'avb_vendor_boot_add_hash_footer_args',
188 'vbmeta' : 'avb_vbmeta_args',
189 'vbmeta_system' : 'avb_vbmeta_system_args',
190 'vbmeta_vendor' : 'avb_vbmeta_vendor_args',
191}
192
193
Narayan Kamatha07bf042017-08-14 14:49:21 +0100194def GetApkCerts(certmap):
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800195 # apply the key remapping to the contents of the file
Tao Baoa3705452019-06-24 15:33:41 -0700196 for apk, cert in certmap.items():
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800197 certmap[apk] = OPTIONS.key_map.get(cert, cert)
198
199 # apply all the -e options, overriding anything in the file
Tao Baoa3705452019-06-24 15:33:41 -0700200 for apk, cert in OPTIONS.extra_apks.items():
Doug Zongkerdecf9952009-12-15 17:27:49 -0800201 if not cert:
202 cert = "PRESIGNED"
Doug Zongkerad88c7c2009-04-14 12:34:27 -0700203 certmap[apk] = OPTIONS.key_map.get(cert, cert)
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800204
Doug Zongkereef39442009-04-02 12:14:19 -0700205 return certmap
206
207
Tao Baoaa7e9932019-03-15 09:37:01 -0700208def GetApexKeys(keys_info, key_map):
209 """Gets APEX payload and container signing keys by applying the mapping rules.
210
Tao Baoe1343992019-03-19 12:24:03 -0700211 Presigned payload / container keys will be set accordingly.
Tao Baoaa7e9932019-03-15 09:37:01 -0700212
213 Args:
214 keys_info: A dict that maps from APEX filenames to a tuple of (payload_key,
215 container_key).
216 key_map: A dict that overrides the keys, specified via command-line input.
217
218 Returns:
219 A dict that contains the updated APEX key mapping, which should be used for
220 the current signing.
Tao Baof98fa102019-04-24 14:51:25 -0700221
222 Raises:
223 AssertionError: On invalid container / payload key overrides.
Tao Baoaa7e9932019-03-15 09:37:01 -0700224 """
225 # Apply all the --extra_apex_payload_key options to override the payload
226 # signing keys in the given keys_info.
227 for apex, key in OPTIONS.extra_apex_payload_keys.items():
Tao Baoe1343992019-03-19 12:24:03 -0700228 if not key:
229 key = 'PRESIGNED'
Tao Bao34223092019-07-11 11:52:52 -0700230 if apex not in keys_info:
231 logger.warning('Failed to find %s in target_files; Ignored', apex)
232 continue
Tao Baoaa7e9932019-03-15 09:37:01 -0700233 keys_info[apex] = (key, keys_info[apex][1])
234
235 # Apply the key remapping to container keys.
236 for apex, (payload_key, container_key) in keys_info.items():
237 keys_info[apex] = (payload_key, key_map.get(container_key, container_key))
238
239 # Apply all the --extra_apks options to override the container keys.
240 for apex, key in OPTIONS.extra_apks.items():
241 # Skip non-APEX containers.
242 if apex not in keys_info:
243 continue
Tao Baoe1343992019-03-19 12:24:03 -0700244 if not key:
245 key = 'PRESIGNED'
Tao Baofa9de0a2019-03-18 10:24:17 -0700246 keys_info[apex] = (keys_info[apex][0], key_map.get(key, key))
Tao Baoaa7e9932019-03-15 09:37:01 -0700247
Tao Baof98fa102019-04-24 14:51:25 -0700248 # A PRESIGNED container entails a PRESIGNED payload. Apply this to all the
249 # APEX key pairs. However, a PRESIGNED container with non-PRESIGNED payload
250 # (overridden via commandline) indicates a config error, which should not be
251 # allowed.
252 for apex, (payload_key, container_key) in keys_info.items():
253 if container_key != 'PRESIGNED':
254 continue
255 if apex in OPTIONS.extra_apex_payload_keys:
256 payload_override = OPTIONS.extra_apex_payload_keys[apex]
257 assert payload_override == '', \
258 ("Invalid APEX key overrides: {} has PRESIGNED container but "
259 "non-PRESIGNED payload key {}").format(apex, payload_override)
260 if payload_key != 'PRESIGNED':
261 print(
262 "Setting {} payload as PRESIGNED due to PRESIGNED container".format(
263 apex))
264 keys_info[apex] = ('PRESIGNED', 'PRESIGNED')
265
Tao Baoaa7e9932019-03-15 09:37:01 -0700266 return keys_info
267
268
Tao Bao93c2a012018-06-19 12:19:35 -0700269def GetApkFileInfo(filename, compressed_extension, skipped_prefixes):
Tao Bao11f955c2018-06-19 12:19:35 -0700270 """Returns the APK info based on the given filename.
271
272 Checks if the given filename (with path) looks like an APK file, by taking the
Tao Bao93c2a012018-06-19 12:19:35 -0700273 compressed extension into consideration. If it appears to be an APK file,
274 further checks if the APK file should be skipped when signing, based on the
275 given path prefixes.
Tao Bao11f955c2018-06-19 12:19:35 -0700276
277 Args:
278 filename: Path to the file.
279 compressed_extension: The extension string of compressed APKs (e.g. ".gz"),
280 or None if there's no compressed APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700281 skipped_prefixes: A set/list/tuple of the path prefixes to be skipped.
Tao Bao11f955c2018-06-19 12:19:35 -0700282
283 Returns:
Tao Bao93c2a012018-06-19 12:19:35 -0700284 (is_apk, is_compressed, should_be_skipped): is_apk indicates whether the
285 given filename is an APK file. is_compressed indicates whether the APK file
286 is compressed (only meaningful when is_apk is True). should_be_skipped
287 indicates whether the filename matches any of the given prefixes to be
288 skipped.
Tao Bao11f955c2018-06-19 12:19:35 -0700289
290 Raises:
Tao Bao93c2a012018-06-19 12:19:35 -0700291 AssertionError: On invalid compressed_extension or skipped_prefixes inputs.
Tao Bao11f955c2018-06-19 12:19:35 -0700292 """
293 assert compressed_extension is None or compressed_extension.startswith('.'), \
294 "Invalid compressed_extension arg: '{}'".format(compressed_extension)
295
Tao Bao93c2a012018-06-19 12:19:35 -0700296 # skipped_prefixes should be one of set/list/tuple types. Other types such as
297 # str shouldn't be accepted.
Tao Baobadceb22019-03-15 09:33:43 -0700298 assert isinstance(skipped_prefixes, (set, list, tuple)), \
299 "Invalid skipped_prefixes input type: {}".format(type(skipped_prefixes))
Tao Bao93c2a012018-06-19 12:19:35 -0700300
Tao Bao11f955c2018-06-19 12:19:35 -0700301 compressed_apk_extension = (
302 ".apk" + compressed_extension if compressed_extension else None)
303 is_apk = (filename.endswith(".apk") or
304 (compressed_apk_extension and
305 filename.endswith(compressed_apk_extension)))
306 if not is_apk:
Tao Bao93c2a012018-06-19 12:19:35 -0700307 return (False, False, False)
Tao Bao11f955c2018-06-19 12:19:35 -0700308
309 is_compressed = (compressed_apk_extension and
310 filename.endswith(compressed_apk_extension))
Tao Bao93c2a012018-06-19 12:19:35 -0700311 should_be_skipped = filename.startswith(tuple(skipped_prefixes))
312 return (True, is_compressed, should_be_skipped)
Tao Bao11f955c2018-06-19 12:19:35 -0700313
314
Tao Baoaa7e9932019-03-15 09:37:01 -0700315def CheckApkAndApexKeysAvailable(input_tf_zip, known_keys,
Tao Baoe1343992019-03-19 12:24:03 -0700316 compressed_extension, apex_keys):
Tao Baoaa7e9932019-03-15 09:37:01 -0700317 """Checks that all the APKs and APEXes have keys specified.
Tao Bao11f955c2018-06-19 12:19:35 -0700318
319 Args:
320 input_tf_zip: An open target_files zip file.
Tao Baoaa7e9932019-03-15 09:37:01 -0700321 known_keys: A set of APKs and APEXes that have known signing keys.
Tao Bao11f955c2018-06-19 12:19:35 -0700322 compressed_extension: The extension string of compressed APKs, such as
Tao Baoaa7e9932019-03-15 09:37:01 -0700323 '.gz', or None if there's no compressed APKs.
Tao Baoe1343992019-03-19 12:24:03 -0700324 apex_keys: A dict that contains the key mapping from APEX name to
325 (payload_key, container_key).
Tao Bao11f955c2018-06-19 12:19:35 -0700326
327 Raises:
Tao Baoaa7e9932019-03-15 09:37:01 -0700328 AssertionError: On finding unknown APKs and APEXes.
Tao Bao11f955c2018-06-19 12:19:35 -0700329 """
Tao Baoaa7e9932019-03-15 09:37:01 -0700330 unknown_files = []
Doug Zongkereb338ef2009-05-20 16:50:49 -0700331 for info in input_tf_zip.infolist():
Tao Baoaa7e9932019-03-15 09:37:01 -0700332 # Handle APEXes first, e.g. SYSTEM/apex/com.android.tzdata.apex.
333 if (info.filename.startswith('SYSTEM/apex') and
334 info.filename.endswith('.apex')):
335 name = os.path.basename(info.filename)
336 if name not in known_keys:
337 unknown_files.append(name)
338 continue
339
340 # And APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700341 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
342 info.filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
343 if not is_apk or should_be_skipped:
Tao Bao11f955c2018-06-19 12:19:35 -0700344 continue
Tao Baoaa7e9932019-03-15 09:37:01 -0700345
Tao Bao11f955c2018-06-19 12:19:35 -0700346 name = os.path.basename(info.filename)
347 if is_compressed:
348 name = name[:-len(compressed_extension)]
Tao Baoaa7e9932019-03-15 09:37:01 -0700349 if name not in known_keys:
350 unknown_files.append(name)
Tao Bao11f955c2018-06-19 12:19:35 -0700351
Tao Baoaa7e9932019-03-15 09:37:01 -0700352 assert not unknown_files, \
Tao Bao11f955c2018-06-19 12:19:35 -0700353 ("No key specified for:\n {}\n"
354 "Use '-e <apkname>=' to specify a key (which may be an empty string to "
Tao Baoaa7e9932019-03-15 09:37:01 -0700355 "not sign this apk).".format("\n ".join(unknown_files)))
Doug Zongkereb338ef2009-05-20 16:50:49 -0700356
Tao Baoe1343992019-03-19 12:24:03 -0700357 # For all the APEXes, double check that we won't have an APEX that has only
Tao Baof98fa102019-04-24 14:51:25 -0700358 # one of the payload / container keys set. Note that non-PRESIGNED container
359 # with PRESIGNED payload could be allowed but currently unsupported. It would
360 # require changing SignApex implementation.
Tao Baoe1343992019-03-19 12:24:03 -0700361 if not apex_keys:
362 return
363
364 invalid_apexes = []
365 for info in input_tf_zip.infolist():
366 if (not info.filename.startswith('SYSTEM/apex') or
367 not info.filename.endswith('.apex')):
368 continue
369
370 name = os.path.basename(info.filename)
371 (payload_key, container_key) = apex_keys[name]
372 if ((payload_key in common.SPECIAL_CERT_STRINGS and
373 container_key not in common.SPECIAL_CERT_STRINGS) or
374 (payload_key not in common.SPECIAL_CERT_STRINGS and
375 container_key in common.SPECIAL_CERT_STRINGS)):
376 invalid_apexes.append(
377 "{}: payload_key {}, container_key {}".format(
378 name, payload_key, container_key))
379
380 assert not invalid_apexes, \
381 "Invalid APEX keys specified:\n {}\n".format(
382 "\n ".join(invalid_apexes))
383
Doug Zongkereb338ef2009-05-20 16:50:49 -0700384
Narayan Kamatha07bf042017-08-14 14:49:21 +0100385def SignApk(data, keyname, pw, platform_api_level, codename_to_api_level_map,
Oleg Aravin8046cb02020-06-02 16:02:38 -0700386 is_compressed, apk_name):
387 unsigned = tempfile.NamedTemporaryFile(suffix='_' + apk_name)
Doug Zongkereef39442009-04-02 12:14:19 -0700388 unsigned.write(data)
389 unsigned.flush()
390
Narayan Kamatha07bf042017-08-14 14:49:21 +0100391 if is_compressed:
392 uncompressed = tempfile.NamedTemporaryFile()
Tao Bao0c28d2d2017-12-24 10:37:38 -0800393 with gzip.open(unsigned.name, "rb") as in_file, \
394 open(uncompressed.name, "wb") as out_file:
Narayan Kamatha07bf042017-08-14 14:49:21 +0100395 shutil.copyfileobj(in_file, out_file)
396
397 # Finally, close the "unsigned" file (which is gzip compressed), and then
398 # replace it with the uncompressed version.
399 #
400 # TODO(narayan): All this nastiness can be avoided if python 3.2 is in use,
401 # we could just gzip / gunzip in-memory buffers instead.
402 unsigned.close()
403 unsigned = uncompressed
404
Oleg Aravin8046cb02020-06-02 16:02:38 -0700405 signed = tempfile.NamedTemporaryFile(suffix='_' + apk_name)
Doug Zongkereef39442009-04-02 12:14:19 -0700406
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800407 # For pre-N builds, don't upgrade to SHA-256 JAR signatures based on the APK's
408 # minSdkVersion to avoid increasing incremental OTA update sizes. If an APK
409 # didn't change, we don't want its signature to change due to the switch
410 # from SHA-1 to SHA-256.
411 # By default, APK signer chooses SHA-256 signatures if the APK's minSdkVersion
412 # is 18 or higher. For pre-N builds we disable this mechanism by pretending
413 # that the APK's minSdkVersion is 1.
414 # For N+ builds, we let APK signer rely on the APK's minSdkVersion to
415 # determine whether to use SHA-256.
416 min_api_level = None
417 if platform_api_level > 23:
418 # Let APK signer choose whether to use SHA-1 or SHA-256, based on the APK's
419 # minSdkVersion attribute
420 min_api_level = None
421 else:
422 # Force APK signer to use SHA-1
423 min_api_level = 1
424
425 common.SignFile(unsigned.name, signed.name, keyname, pw,
Tao Bao0c28d2d2017-12-24 10:37:38 -0800426 min_api_level=min_api_level,
427 codename_to_api_level_map=codename_to_api_level_map)
Doug Zongkereef39442009-04-02 12:14:19 -0700428
Tao Bao0c28d2d2017-12-24 10:37:38 -0800429 data = None
Narayan Kamatha07bf042017-08-14 14:49:21 +0100430 if is_compressed:
431 # Recompress the file after it has been signed.
432 compressed = tempfile.NamedTemporaryFile()
Tao Bao0c28d2d2017-12-24 10:37:38 -0800433 with open(signed.name, "rb") as in_file, \
434 gzip.open(compressed.name, "wb") as out_file:
Narayan Kamatha07bf042017-08-14 14:49:21 +0100435 shutil.copyfileobj(in_file, out_file)
436
437 data = compressed.read()
438 compressed.close()
439 else:
440 data = signed.read()
441
Doug Zongkereef39442009-04-02 12:14:19 -0700442 unsigned.close()
443 signed.close()
444
445 return data
446
Kelvin Zhang119f2792021-02-10 12:45:24 -0500447def IsBuildPropFile(filename):
448 return filename in (
449 "SYSTEM/etc/prop.default",
450 "BOOT/RAMDISK/prop.default",
451 "RECOVERY/RAMDISK/prop.default",
452
453 "VENDOR_BOOT/RAMDISK/default.prop",
454 "VENDOR_BOOT/RAMDISK/prop.default",
455
456 # ROOT/default.prop is a legacy path, but may still exist for upgrading
457 # devices that don't support `property_overrides_split_enabled`.
458 "ROOT/default.prop",
459
460 # RECOVERY/RAMDISK/default.prop is a legacy path, but will always exist
461 # as a symlink in the current code. So it's a no-op here. Keeping the
462 # path here for clarity.
463 "RECOVERY/RAMDISK/default.prop") or filename.endswith("build.prop")
Doug Zongkereef39442009-04-02 12:14:19 -0700464
Doug Zongker412c02f2014-02-13 10:58:24 -0800465def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -0700466 apk_keys, apex_keys, key_passwords,
467 platform_api_level, codename_to_api_level_map,
Narayan Kamatha07bf042017-08-14 14:49:21 +0100468 compressed_extension):
Tao Bao93c2a012018-06-19 12:19:35 -0700469 # maxsize measures the maximum filename length, including the ones to be
470 # skipped.
Tao Bao0c28d2d2017-12-24 10:37:38 -0800471 maxsize = max(
472 [len(os.path.basename(i.filename)) for i in input_tf_zip.infolist()
Tao Bao93c2a012018-06-19 12:19:35 -0700473 if GetApkFileInfo(i.filename, compressed_extension, [])[0]])
Tao Baoa80ed222016-06-16 14:41:24 -0700474 system_root_image = misc_info.get("system_root_image") == "true"
Doug Zongker412c02f2014-02-13 10:58:24 -0800475
Doug Zongkereef39442009-04-02 12:14:19 -0700476 for info in input_tf_zip.infolist():
Tao Bao11f955c2018-06-19 12:19:35 -0700477 filename = info.filename
478 if filename.startswith("IMAGES/"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700479 continue
Doug Zongker3c84f562014-07-31 11:06:30 -0700480
Tao Bao04808502019-07-25 23:11:41 -0700481 # Skip OTA-specific images (e.g. split super images), which will be
482 # re-generated during signing.
Tao Bao33bf2682019-01-11 12:37:35 -0800483 if filename.startswith("OTA/") and filename.endswith(".img"):
484 continue
485
Tao Bao11f955c2018-06-19 12:19:35 -0700486 data = input_tf_zip.read(filename)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700487 out_info = copy.copy(info)
Tao Bao93c2a012018-06-19 12:19:35 -0700488 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
489 filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
490
491 if is_apk and should_be_skipped:
492 # Copy skipped APKs verbatim.
493 print(
494 "NOT signing: %s\n"
495 " (skipped due to matching prefix)" % (filename,))
496 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker412c02f2014-02-13 10:58:24 -0800497
Tao Baof2cffbd2015-07-22 12:33:18 -0700498 # Sign APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700499 elif is_apk:
Tao Bao11f955c2018-06-19 12:19:35 -0700500 name = os.path.basename(filename)
Narayan Kamatha07bf042017-08-14 14:49:21 +0100501 if is_compressed:
502 name = name[:-len(compressed_extension)]
503
Tao Baoaa7e9932019-03-15 09:37:01 -0700504 key = apk_keys[name]
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800505 if key not in common.SPECIAL_CERT_STRINGS:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800506 print(" signing: %-*s (%s)" % (maxsize, name, key))
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800507 signed_data = SignApk(data, key, key_passwords[key], platform_api_level,
Oleg Aravin8046cb02020-06-02 16:02:38 -0700508 codename_to_api_level_map, is_compressed, name)
Tao Bao2ed665a2015-04-01 11:21:55 -0700509 common.ZipWriteStr(output_tf_zip, out_info, signed_data)
Doug Zongkereef39442009-04-02 12:14:19 -0700510 else:
511 # an APK we're not supposed to sign.
Tao Bao93c2a012018-06-19 12:19:35 -0700512 print(
513 "NOT signing: %s\n"
514 " (skipped due to special cert string)" % (name,))
Tao Bao2ed665a2015-04-01 11:21:55 -0700515 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoa80ed222016-06-16 14:41:24 -0700516
Tao Baoaa7e9932019-03-15 09:37:01 -0700517 # Sign bundled APEX files.
518 elif filename.startswith("SYSTEM/apex") and filename.endswith(".apex"):
519 name = os.path.basename(filename)
520 payload_key, container_key = apex_keys[name]
521
Tao Baoe1343992019-03-19 12:24:03 -0700522 # We've asserted not having a case with only one of them PRESIGNED.
523 if (payload_key not in common.SPECIAL_CERT_STRINGS and
524 container_key not in common.SPECIAL_CERT_STRINGS):
525 print(" signing: %-*s container (%s)" % (
526 maxsize, name, container_key))
527 print(" : %-*s payload (%s)" % (
528 maxsize, name, payload_key))
Tao Baoaa7e9932019-03-15 09:37:01 -0700529
Tao Baoe7354ba2019-05-09 16:54:15 -0700530 signed_apex = apex_utils.SignApex(
Tao Bao1ac886e2019-06-26 11:58:22 -0700531 misc_info['avb_avbtool'],
Tao Baoe1343992019-03-19 12:24:03 -0700532 data,
533 payload_key,
534 container_key,
Oleh Cherpake555ab12020-10-05 17:04:59 +0300535 key_passwords,
Tianjie Xu88a759d2020-01-23 10:47:54 -0800536 apk_keys,
Tao Baoe1343992019-03-19 12:24:03 -0700537 codename_to_api_level_map,
Tao Bao448004a2019-09-19 07:55:02 -0700538 no_hashtree=True,
539 signing_args=OPTIONS.avb_extra_args.get('apex'))
Tao Baoe1343992019-03-19 12:24:03 -0700540 common.ZipWrite(output_tf_zip, signed_apex, filename)
Tao Baoaa7e9932019-03-15 09:37:01 -0700541
Tao Baoe1343992019-03-19 12:24:03 -0700542 else:
543 print(
544 "NOT signing: %s\n"
545 " (skipped due to special cert string)" % (name,))
546 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoaa7e9932019-03-15 09:37:01 -0700547
548 # AVB public keys for the installed APEXes, which will be updated later.
549 elif (os.path.dirname(filename) == 'SYSTEM/etc/security/apex' and
550 filename != 'SYSTEM/etc/security/apex/'):
551 continue
552
Tao Baoa80ed222016-06-16 14:41:24 -0700553 # System properties.
Kelvin Zhang119f2792021-02-10 12:45:24 -0500554 elif IsBuildPropFile(filename):
Tao Bao11f955c2018-06-19 12:19:35 -0700555 print("Rewriting %s:" % (filename,))
Hung-ying Tyan7eb6a922017-05-01 21:56:26 +0800556 if stat.S_ISLNK(info.external_attr >> 16):
557 new_data = data
558 else:
Tao Baoa3705452019-06-24 15:33:41 -0700559 new_data = RewriteProps(data.decode())
Tao Bao2ed665a2015-04-01 11:21:55 -0700560 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700561
Tao Bao66472632017-12-04 17:16:36 -0800562 # Replace the certs in *mac_permissions.xml (there could be multiple, such
563 # as {system,vendor}/etc/selinux/{plat,nonplat}_mac_permissions.xml).
Tao Bao11f955c2018-06-19 12:19:35 -0700564 elif filename.endswith("mac_permissions.xml"):
565 print("Rewriting %s with new keys." % (filename,))
Tao Baoa3705452019-06-24 15:33:41 -0700566 new_data = ReplaceCerts(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
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700569 # Ask add_img_to_target_files to rebuild the recovery patch if needed.
Tao Bao11f955c2018-06-19 12:19:35 -0700570 elif filename in ("SYSTEM/recovery-from-boot.p",
Robin Leeda427de2020-01-03 19:16:32 +0100571 "VENDOR/recovery-from-boot.p",
572
Tao Bao11f955c2018-06-19 12:19:35 -0700573 "SYSTEM/etc/recovery.img",
Robin Leeda427de2020-01-03 19:16:32 +0100574 "VENDOR/etc/recovery.img",
575
576 "SYSTEM/bin/install-recovery.sh",
577 "VENDOR/bin/install-recovery.sh"):
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700578 OPTIONS.rebuild_recovery = True
Tao Baoa80ed222016-06-16 14:41:24 -0700579
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700580 # Don't copy OTA certs if we're replacing them.
Tianjie Xu2df23d72019-10-15 18:06:25 -0700581 # Replacement of update-payload-key.pub.pem was removed in b/116660991.
Tao Bao696bb332018-08-17 16:27:01 -0700582 elif (
583 OPTIONS.replace_ota_keys and
584 filename in (
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700585 "BOOT/RAMDISK/system/etc/security/otacerts.zip",
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700586 "RECOVERY/RAMDISK/system/etc/security/otacerts.zip",
Tianjie Xu2df23d72019-10-15 18:06:25 -0700587 "SYSTEM/etc/security/otacerts.zip")):
Doug Zongker412c02f2014-02-13 10:58:24 -0800588 pass
Tao Baoa80ed222016-06-16 14:41:24 -0700589
Tao Bao46a59992017-06-05 11:55:16 -0700590 # Skip META/misc_info.txt since we will write back the new values later.
Tao Bao11f955c2018-06-19 12:19:35 -0700591 elif filename == "META/misc_info.txt":
Geremy Condraf19b3652014-07-29 17:54:54 -0700592 pass
Tao Bao8adcfd12016-06-17 17:01:22 -0700593
594 # Skip verity public key if we will replace it.
Michael Runge947894f2014-10-14 20:58:38 -0700595 elif (OPTIONS.replace_verity_public_key and
Tao Bao11f955c2018-06-19 12:19:35 -0700596 filename in ("BOOT/RAMDISK/verity_key",
597 "ROOT/verity_key")):
Geremy Condraf19b3652014-07-29 17:54:54 -0700598 pass
Bowgo Tsai2fe786a2020-02-21 17:48:18 +0800599 elif (OPTIONS.remove_avb_public_keys and
600 (filename.startswith("BOOT/RAMDISK/avb/") or
601 filename.startswith("BOOT/RAMDISK/first_stage_ramdisk/avb/"))):
Kelvin Zhang0876c412020-06-23 15:06:58 -0400602 matched_removal = False
603 for key_to_remove in OPTIONS.remove_avb_public_keys:
604 if filename.endswith(key_to_remove):
605 matched_removal = True
606 print("Removing AVB public key from ramdisk: %s" % filename)
607 break
608 if not matched_removal:
609 # Copy it verbatim if we don't want to remove it.
610 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoa80ed222016-06-16 14:41:24 -0700611
Tao Bao8adcfd12016-06-17 17:01:22 -0700612 # Skip verity keyid (for system_root_image use) if we will replace it.
Tao Bao11f955c2018-06-19 12:19:35 -0700613 elif OPTIONS.replace_verity_keyid and filename == "BOOT/cmdline":
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700614 pass
615
Tianjie Xu4f099002016-08-11 18:04:27 -0700616 # Skip the care_map as we will regenerate the system/vendor images.
Kelvin Zhang0876c412020-06-23 15:06:58 -0400617 elif filename in ["META/care_map.pb", "META/care_map.txt"]:
Tianjie Xu4f099002016-08-11 18:04:27 -0700618 pass
619
Kelvin Zhang5f0fcee2021-01-19 15:30:46 -0500620 # Skip apex_info.pb because we sign/modify apexes
621 elif filename == "META/apex_info.pb":
622 pass
623
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800624 # Updates system_other.avbpubkey in /product/etc/.
625 elif filename in (
626 "PRODUCT/etc/security/avb/system_other.avbpubkey",
627 "SYSTEM/product/etc/security/avb/system_other.avbpubkey"):
628 # Only update system_other's public key, if the corresponding signing
629 # key is specified via --avb_system_other_key.
630 signing_key = OPTIONS.avb_keys.get("system_other")
631 if signing_key:
Tao Bao1ac886e2019-06-26 11:58:22 -0700632 public_key = common.ExtractAvbPublicKey(
633 misc_info['avb_avbtool'], signing_key)
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800634 print(" Rewriting AVB public key of system_other in /product")
635 common.ZipWrite(output_tf_zip, public_key, filename)
636
Bowgo Tsai78369eb2019-04-23 12:28:44 +0800637 # Should NOT sign boot-debug.img.
638 elif filename in (
639 "BOOT/RAMDISK/force_debuggable",
Bowgo Tsai2fe786a2020-02-21 17:48:18 +0800640 "BOOT/RAMDISK/first_stage_ramdisk/force_debuggable"):
Bowgo Tsai78369eb2019-04-23 12:28:44 +0800641 raise common.ExternalError("debuggable boot.img cannot be signed")
642
Tao Baoa80ed222016-06-16 14:41:24 -0700643 # A non-APK file; copy it verbatim.
Doug Zongkereef39442009-04-02 12:14:19 -0700644 else:
Tao Bao2ed665a2015-04-01 11:21:55 -0700645 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700646
Doug Zongker412c02f2014-02-13 10:58:24 -0800647 if OPTIONS.replace_ota_keys:
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700648 ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info)
Doug Zongker412c02f2014-02-13 10:58:24 -0800649
Tao Bao46a59992017-06-05 11:55:16 -0700650 # Replace the keyid string in misc_info dict.
Tao Bao8adcfd12016-06-17 17:01:22 -0700651 if OPTIONS.replace_verity_private_key:
Tao Bao46a59992017-06-05 11:55:16 -0700652 ReplaceVerityPrivateKey(misc_info, OPTIONS.replace_verity_private_key[1])
Tao Bao8adcfd12016-06-17 17:01:22 -0700653
654 if OPTIONS.replace_verity_public_key:
Tao Baoc9981932019-09-16 12:10:43 -0700655 # Replace the one in root dir in system.img.
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700656 ReplaceVerityPublicKey(
Tao Baoc9981932019-09-16 12:10:43 -0700657 output_tf_zip, 'ROOT/verity_key', OPTIONS.replace_verity_public_key[1])
658
659 if not system_root_image:
660 # Additionally replace the copy in ramdisk if not using system-as-root.
661 ReplaceVerityPublicKey(
662 output_tf_zip,
663 'BOOT/RAMDISK/verity_key',
664 OPTIONS.replace_verity_public_key[1])
Tao Bao8adcfd12016-06-17 17:01:22 -0700665
666 # Replace the keyid string in BOOT/cmdline.
667 if OPTIONS.replace_verity_keyid:
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700668 ReplaceVerityKeyId(input_tf_zip, output_tf_zip,
669 OPTIONS.replace_verity_keyid[1])
Doug Zongker412c02f2014-02-13 10:58:24 -0800670
Tao Bao639118f2017-06-19 15:48:02 -0700671 # Replace the AVB signing keys, if any.
672 ReplaceAvbSigningKeys(misc_info)
673
Tao Bao19b02fe2019-10-09 00:04:28 -0700674 # Rewrite the props in AVB signing args.
675 if misc_info.get('avb_enable') == 'true':
676 RewriteAvbProps(misc_info)
677
Tao Bao46a59992017-06-05 11:55:16 -0700678 # Write back misc_info with the latest values.
679 ReplaceMiscInfoTxt(input_tf_zip, output_tf_zip, misc_info)
680
Doug Zongker8e931bf2009-04-06 15:21:45 -0700681
Robert Craig817c5742013-04-19 10:59:22 -0400682def ReplaceCerts(data):
Tao Bao66472632017-12-04 17:16:36 -0800683 """Replaces all the occurences of X.509 certs with the new ones.
Robert Craig817c5742013-04-19 10:59:22 -0400684
Tao Bao66472632017-12-04 17:16:36 -0800685 The mapping info is read from OPTIONS.key_map. Non-existent certificate will
686 be skipped. After the replacement, it additionally checks for duplicate
687 entries, which would otherwise fail the policy loading code in
688 frameworks/base/services/core/java/com/android/server/pm/SELinuxMMAC.java.
689
690 Args:
691 data: Input string that contains a set of X.509 certs.
692
693 Returns:
694 A string after the replacement.
695
696 Raises:
697 AssertionError: On finding duplicate entries.
698 """
Tao Baoa3705452019-06-24 15:33:41 -0700699 for old, new in OPTIONS.key_map.items():
Tao Bao66472632017-12-04 17:16:36 -0800700 if OPTIONS.verbose:
701 print(" Replacing %s.x509.pem with %s.x509.pem" % (old, new))
702
703 try:
704 with open(old + ".x509.pem") as old_fp:
705 old_cert16 = base64.b16encode(
Tao Baoa3705452019-06-24 15:33:41 -0700706 common.ParseCertificate(old_fp.read())).decode().lower()
Tao Bao66472632017-12-04 17:16:36 -0800707 with open(new + ".x509.pem") as new_fp:
708 new_cert16 = base64.b16encode(
Tao Baoa3705452019-06-24 15:33:41 -0700709 common.ParseCertificate(new_fp.read())).decode().lower()
Tao Bao66472632017-12-04 17:16:36 -0800710 except IOError as e:
711 if OPTIONS.verbose or e.errno != errno.ENOENT:
712 print(" Error accessing %s: %s.\nSkip replacing %s.x509.pem with "
713 "%s.x509.pem." % (e.filename, e.strerror, old, new))
714 continue
715
716 # Only match entire certs.
717 pattern = "\\b" + old_cert16 + "\\b"
718 (data, num) = re.subn(pattern, new_cert16, data, flags=re.IGNORECASE)
719
720 if OPTIONS.verbose:
721 print(" Replaced %d occurence(s) of %s.x509.pem with %s.x509.pem" % (
722 num, old, new))
723
724 # Verify that there're no duplicate entries after the replacement. Note that
725 # it's only checking entries with global seinfo at the moment (i.e. ignoring
726 # the ones with inner packages). (Bug: 69479366)
727 root = ElementTree.fromstring(data)
728 signatures = [signer.attrib['signature'] for signer in root.findall('signer')]
729 assert len(signatures) == len(set(signatures)), \
730 "Found duplicate entries after cert replacement: {}".format(data)
Robert Craig817c5742013-04-19 10:59:22 -0400731
732 return data
733
734
Doug Zongkerc09abc82010-01-11 13:09:15 -0800735def EditTags(tags):
Tao Baoa7054ee2017-12-08 14:42:16 -0800736 """Applies the edits to the tag string as specified in OPTIONS.tag_changes.
737
738 Args:
739 tags: The input string that contains comma-separated tags.
740
741 Returns:
742 The updated tags (comma-separated and sorted).
743 """
Doug Zongkerc09abc82010-01-11 13:09:15 -0800744 tags = set(tags.split(","))
745 for ch in OPTIONS.tag_changes:
746 if ch[0] == "-":
747 tags.discard(ch[1:])
748 elif ch[0] == "+":
749 tags.add(ch[1:])
750 return ",".join(sorted(tags))
751
752
Tao Baoa7054ee2017-12-08 14:42:16 -0800753def RewriteProps(data):
754 """Rewrites the system properties in the given string.
755
756 Each property is expected in 'key=value' format. The properties that contain
757 build tags (i.e. test-keys, dev-keys) will be updated accordingly by calling
758 EditTags().
759
760 Args:
761 data: Input string, separated by newlines.
762
763 Returns:
764 The string with modified properties.
765 """
Doug Zongker17aa9442009-04-17 10:15:58 -0700766 output = []
767 for line in data.split("\n"):
768 line = line.strip()
769 original_line = line
Michael Rungedc2661a2014-06-03 14:43:11 -0700770 if line and line[0] != '#' and "=" in line:
Doug Zongker17aa9442009-04-17 10:15:58 -0700771 key, value = line.split("=", 1)
Magnus Strandh234f4b42019-05-01 23:09:30 +0200772 if (key.startswith("ro.") and
773 key.endswith((".build.fingerprint", ".build.thumbprint"))):
Doug Zongkerc09abc82010-01-11 13:09:15 -0800774 pieces = value.split("/")
775 pieces[-1] = EditTags(pieces[-1])
776 value = "/".join(pieces)
Tao Baocb7ff772015-09-11 15:27:56 -0700777 elif key == "ro.bootimage.build.fingerprint":
778 pieces = value.split("/")
779 pieces[-1] = EditTags(pieces[-1])
780 value = "/".join(pieces)
Doug Zongker17aa9442009-04-17 10:15:58 -0700781 elif key == "ro.build.description":
Doug Zongkerc09abc82010-01-11 13:09:15 -0800782 pieces = value.split(" ")
Doug Zongker17aa9442009-04-17 10:15:58 -0700783 assert len(pieces) == 5
Doug Zongkerc09abc82010-01-11 13:09:15 -0800784 pieces[-1] = EditTags(pieces[-1])
785 value = " ".join(pieces)
Magnus Strandh234f4b42019-05-01 23:09:30 +0200786 elif key.startswith("ro.") and key.endswith(".build.tags"):
Doug Zongkerc09abc82010-01-11 13:09:15 -0800787 value = EditTags(value)
Doug Zongkera8608a72013-07-23 11:51:04 -0700788 elif key == "ro.build.display.id":
789 # change, eg, "JWR66N dev-keys" to "JWR66N"
790 value = value.split()
Michael Rungedc2661a2014-06-03 14:43:11 -0700791 if len(value) > 1 and value[-1].endswith("-keys"):
Andrew Boie73d5abb2013-12-11 12:42:03 -0800792 value.pop()
793 value = " ".join(value)
Doug Zongkerc09abc82010-01-11 13:09:15 -0800794 line = key + "=" + value
Doug Zongker17aa9442009-04-17 10:15:58 -0700795 if line != original_line:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800796 print(" replace: ", original_line)
797 print(" with: ", line)
Doug Zongker17aa9442009-04-17 10:15:58 -0700798 output.append(line)
799 return "\n".join(output) + "\n"
800
801
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700802def WriteOtacerts(output_zip, filename, keys):
803 """Constructs a zipfile from given keys; and writes it to output_zip.
804
805 Args:
806 output_zip: The output target_files zip.
807 filename: The archive name in the output zip.
808 keys: A list of public keys to use during OTA package verification.
809 """
Tao Baobb733882019-07-24 23:31:19 -0700810 temp_file = io.BytesIO()
Kelvin Zhang928c2342020-09-22 16:15:57 -0400811 certs_zip = zipfile.ZipFile(temp_file, "w", allowZip64=True)
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700812 for k in keys:
813 common.ZipWrite(certs_zip, k)
814 common.ZipClose(certs_zip)
815 common.ZipWriteStr(output_zip, filename, temp_file.getvalue())
816
817
Doug Zongker831840e2011-09-22 10:28:04 -0700818def ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info):
Doug Zongker8e931bf2009-04-06 15:21:45 -0700819 try:
820 keylist = input_tf_zip.read("META/otakeys.txt").split()
821 except KeyError:
T.R. Fullharta28acc62013-03-18 10:31:26 -0700822 raise common.ExternalError("can't read META/otakeys.txt from input")
Doug Zongker8e931bf2009-04-06 15:21:45 -0700823
Tao Baof718f902017-11-09 10:10:10 -0800824 extra_recovery_keys = misc_info.get("extra_recovery_keys")
Doug Zongkere121d6a2011-02-01 14:13:52 -0800825 if extra_recovery_keys:
826 extra_recovery_keys = [OPTIONS.key_map.get(k, k) + ".x509.pem"
827 for k in extra_recovery_keys.split()]
828 if extra_recovery_keys:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800829 print("extra recovery-only key(s): " + ", ".join(extra_recovery_keys))
Doug Zongkere121d6a2011-02-01 14:13:52 -0800830 else:
831 extra_recovery_keys = []
832
Doug Zongker8e931bf2009-04-06 15:21:45 -0700833 mapped_keys = []
834 for k in keylist:
835 m = re.match(r"^(.*)\.x509\.pem$", k)
836 if not m:
Doug Zongker412c02f2014-02-13 10:58:24 -0800837 raise common.ExternalError(
838 "can't parse \"%s\" from META/otakeys.txt" % (k,))
Doug Zongker8e931bf2009-04-06 15:21:45 -0700839 k = m.group(1)
840 mapped_keys.append(OPTIONS.key_map.get(k, k) + ".x509.pem")
841
Doug Zongkere05628c2009-08-20 17:38:42 -0700842 if mapped_keys:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800843 print("using:\n ", "\n ".join(mapped_keys))
844 print("for OTA package verification")
Doug Zongkere05628c2009-08-20 17:38:42 -0700845 else:
Doug Zongker831840e2011-09-22 10:28:04 -0700846 devkey = misc_info.get("default_system_dev_certificate",
Dan Willemsen0ab1be62019-04-09 21:35:37 -0700847 "build/make/target/product/security/testkey")
Tao Baof718f902017-11-09 10:10:10 -0800848 mapped_devkey = OPTIONS.key_map.get(devkey, devkey)
849 if mapped_devkey != devkey:
850 misc_info["default_system_dev_certificate"] = mapped_devkey
851 mapped_keys.append(mapped_devkey + ".x509.pem")
Tao Baoa80ed222016-06-16 14:41:24 -0700852 print("META/otakeys.txt has no keys; using %s for OTA package"
853 " verification." % (mapped_keys[0],))
Doug Zongker8e931bf2009-04-06 15:21:45 -0700854
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700855 # recovery now uses the same x509.pem version of the keys.
Doug Zongkere121d6a2011-02-01 14:13:52 -0800856 # extra_recovery_keys are used only in recovery.
Tom Cherry2929cad2018-09-20 11:04:37 -0700857 if misc_info.get("recovery_as_boot") == "true":
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700858 recovery_keys_location = "BOOT/RAMDISK/system/etc/security/otacerts.zip"
Tao Baoa80ed222016-06-16 14:41:24 -0700859 else:
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700860 recovery_keys_location = "RECOVERY/RAMDISK/system/etc/security/otacerts.zip"
861
862 WriteOtacerts(output_tf_zip, recovery_keys_location,
863 mapped_keys + extra_recovery_keys)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700864
865 # SystemUpdateActivity uses the x509.pem version of the keys, but
866 # put into a zipfile system/etc/security/otacerts.zip.
Doug Zongkere121d6a2011-02-01 14:13:52 -0800867 # We DO NOT include the extra_recovery_keys (if any) here.
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700868 WriteOtacerts(output_tf_zip, "SYSTEM/etc/security/otacerts.zip", mapped_keys)
Doug Zongkereef39442009-04-02 12:14:19 -0700869
Tao Baoa80ed222016-06-16 14:41:24 -0700870
Tao Bao0c28d2d2017-12-24 10:37:38 -0800871def ReplaceVerityPublicKey(output_zip, filename, key_path):
872 """Replaces the verity public key at the given path in the given zip.
873
874 Args:
875 output_zip: The output target_files zip.
876 filename: The archive name in the output zip.
877 key_path: The path to the public key.
878 """
879 print("Replacing verity public key with %s" % (key_path,))
880 common.ZipWrite(output_zip, key_path, arcname=filename)
Geremy Condraf19b3652014-07-29 17:54:54 -0700881
Tao Bao8adcfd12016-06-17 17:01:22 -0700882
Tao Bao46a59992017-06-05 11:55:16 -0700883def ReplaceVerityPrivateKey(misc_info, key_path):
Tao Bao0c28d2d2017-12-24 10:37:38 -0800884 """Replaces the verity private key in misc_info dict.
885
886 Args:
887 misc_info: The info dict.
888 key_path: The path to the private key in PKCS#8 format.
889 """
890 print("Replacing verity private key with %s" % (key_path,))
Andrew Boied083f0b2014-09-15 16:01:07 -0700891 misc_info["verity_key"] = key_path
Doug Zongkereef39442009-04-02 12:14:19 -0700892
Tao Bao8adcfd12016-06-17 17:01:22 -0700893
Tao Baoe838d142017-12-23 23:44:48 -0800894def ReplaceVerityKeyId(input_zip, output_zip, key_path):
895 """Replaces the veritykeyid parameter in BOOT/cmdline.
896
897 Args:
898 input_zip: The input target_files zip, which should be already open.
899 output_zip: The output target_files zip, which should be already open and
900 writable.
901 key_path: The path to the PEM encoded X.509 certificate.
902 """
Tao Baoa3705452019-06-24 15:33:41 -0700903 in_cmdline = input_zip.read("BOOT/cmdline").decode()
Tao Baoe838d142017-12-23 23:44:48 -0800904 # Copy in_cmdline to output_zip if veritykeyid is not present.
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700905 if "veritykeyid" not in in_cmdline:
Tao Baoe838d142017-12-23 23:44:48 -0800906 common.ZipWriteStr(output_zip, "BOOT/cmdline", in_cmdline)
907 return
908
Tao Bao0c28d2d2017-12-24 10:37:38 -0800909 out_buffer = []
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700910 for param in in_cmdline.split():
Tao Baoe838d142017-12-23 23:44:48 -0800911 if "veritykeyid" not in param:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800912 out_buffer.append(param)
Tao Baoe838d142017-12-23 23:44:48 -0800913 continue
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700914
Tao Baoe838d142017-12-23 23:44:48 -0800915 # Extract keyid using openssl command.
916 p = common.Run(["openssl", "x509", "-in", key_path, "-text"],
Tao Baode1d4792018-02-20 10:05:46 -0800917 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
Tao Baoe838d142017-12-23 23:44:48 -0800918 keyid, stderr = p.communicate()
919 assert p.returncode == 0, "Failed to dump certificate: {}".format(stderr)
920 keyid = re.search(
921 r'keyid:([0-9a-fA-F:]*)', keyid).group(1).replace(':', '').lower()
922 print("Replacing verity keyid with {}".format(keyid))
923 out_buffer.append("veritykeyid=id:%s" % (keyid,))
924
925 out_cmdline = ' '.join(out_buffer).strip() + '\n'
926 common.ZipWriteStr(output_zip, "BOOT/cmdline", out_cmdline)
Tao Bao46a59992017-06-05 11:55:16 -0700927
928
929def ReplaceMiscInfoTxt(input_zip, output_zip, misc_info):
930 """Replaces META/misc_info.txt.
931
932 Only writes back the ones in the original META/misc_info.txt. Because the
933 current in-memory dict contains additional items computed at runtime.
934 """
935 misc_info_old = common.LoadDictionaryFromLines(
Tao Baoa3705452019-06-24 15:33:41 -0700936 input_zip.read('META/misc_info.txt').decode().split('\n'))
Tao Bao46a59992017-06-05 11:55:16 -0700937 items = []
938 for key in sorted(misc_info):
939 if key in misc_info_old:
940 items.append('%s=%s' % (key, misc_info[key]))
941 common.ZipWriteStr(output_zip, "META/misc_info.txt", '\n'.join(items))
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700942
Tao Bao8adcfd12016-06-17 17:01:22 -0700943
Tao Bao639118f2017-06-19 15:48:02 -0700944def ReplaceAvbSigningKeys(misc_info):
945 """Replaces the AVB signing keys."""
946
Tao Bao639118f2017-06-19 15:48:02 -0700947 def ReplaceAvbPartitionSigningKey(partition):
948 key = OPTIONS.avb_keys.get(partition)
949 if not key:
950 return
951
952 algorithm = OPTIONS.avb_algorithms.get(partition)
953 assert algorithm, 'Missing AVB signing algorithm for %s' % (partition,)
954
Tao Bao0c28d2d2017-12-24 10:37:38 -0800955 print('Replacing AVB signing key for %s with "%s" (%s)' % (
956 partition, key, algorithm))
Tao Bao639118f2017-06-19 15:48:02 -0700957 misc_info['avb_' + partition + '_algorithm'] = algorithm
958 misc_info['avb_' + partition + '_key_path'] = key
959
960 extra_args = OPTIONS.avb_extra_args.get(partition)
961 if extra_args:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800962 print('Setting extra AVB signing args for %s to "%s"' % (
963 partition, extra_args))
Kelvin Zhang0876c412020-06-23 15:06:58 -0400964 args_key = AVB_FOOTER_ARGS_BY_PARTITION.get(
965 partition,
966 # custom partition
967 "avb_{}_add_hashtree_footer_args".format(partition))
Tao Bao639118f2017-06-19 15:48:02 -0700968 misc_info[args_key] = (misc_info.get(args_key, '') + ' ' + extra_args)
969
970 for partition in AVB_FOOTER_ARGS_BY_PARTITION:
971 ReplaceAvbPartitionSigningKey(partition)
972
Hongguang Chenf23364d2020-04-27 18:36:36 -0700973 for custom_partition in misc_info.get(
974 "avb_custom_images_partition_list", "").strip().split():
975 ReplaceAvbPartitionSigningKey(custom_partition)
976
Tao Bao639118f2017-06-19 15:48:02 -0700977
Tao Bao19b02fe2019-10-09 00:04:28 -0700978def RewriteAvbProps(misc_info):
979 """Rewrites the props in AVB signing args."""
980 for partition, args_key in AVB_FOOTER_ARGS_BY_PARTITION.items():
981 args = misc_info.get(args_key)
982 if not args:
983 continue
984
985 tokens = []
986 changed = False
987 for token in args.split(' '):
988 fingerprint_key = 'com.android.build.{}.fingerprint'.format(partition)
989 if not token.startswith(fingerprint_key):
990 tokens.append(token)
991 continue
992 prefix, tag = token.rsplit('/', 1)
993 tokens.append('{}/{}'.format(prefix, EditTags(tag)))
994 changed = True
995
996 if changed:
997 result = ' '.join(tokens)
998 print('Rewriting AVB prop for {}:\n'.format(partition))
999 print(' replace: {}'.format(args))
1000 print(' with: {}'.format(result))
1001 misc_info[args_key] = result
1002
1003
Doug Zongker831840e2011-09-22 10:28:04 -07001004def BuildKeyMap(misc_info, key_mapping_options):
1005 for s, d in key_mapping_options:
1006 if s is None: # -d option
1007 devkey = misc_info.get("default_system_dev_certificate",
Dan Willemsen0ab1be62019-04-09 21:35:37 -07001008 "build/make/target/product/security/testkey")
Doug Zongker831840e2011-09-22 10:28:04 -07001009 devkeydir = os.path.dirname(devkey)
1010
1011 OPTIONS.key_map.update({
1012 devkeydir + "/testkey": d + "/releasekey",
1013 devkeydir + "/devkey": d + "/releasekey",
1014 devkeydir + "/media": d + "/media",
1015 devkeydir + "/shared": d + "/shared",
1016 devkeydir + "/platform": d + "/platform",
Oleh Cherpak982e6082019-12-10 12:58:54 +02001017 devkeydir + "/networkstack": d + "/networkstack",
Doug Zongker831840e2011-09-22 10:28:04 -07001018 })
1019 else:
1020 OPTIONS.key_map[s] = d
1021
1022
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001023def GetApiLevelAndCodename(input_tf_zip):
Tao Baoa3705452019-06-24 15:33:41 -07001024 data = input_tf_zip.read("SYSTEM/build.prop").decode()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001025 api_level = None
1026 codename = None
1027 for line in data.split("\n"):
1028 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001029 if line and line[0] != '#' and "=" in line:
1030 key, value = line.split("=", 1)
1031 key = key.strip()
1032 if key == "ro.build.version.sdk":
1033 api_level = int(value.strip())
1034 elif key == "ro.build.version.codename":
1035 codename = value.strip()
1036
1037 if api_level is None:
1038 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
1039 if codename is None:
1040 raise ValueError("No ro.build.version.codename in SYSTEM/build.prop")
1041
1042 return (api_level, codename)
1043
1044
1045def GetCodenameToApiLevelMap(input_tf_zip):
Tao Baoa3705452019-06-24 15:33:41 -07001046 data = input_tf_zip.read("SYSTEM/build.prop").decode()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001047 api_level = None
1048 codenames = None
1049 for line in data.split("\n"):
1050 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001051 if line and line[0] != '#' and "=" in line:
1052 key, value = line.split("=", 1)
1053 key = key.strip()
1054 if key == "ro.build.version.sdk":
1055 api_level = int(value.strip())
1056 elif key == "ro.build.version.all_codenames":
1057 codenames = value.strip().split(",")
1058
1059 if api_level is None:
1060 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
1061 if codenames is None:
1062 raise ValueError("No ro.build.version.all_codenames in SYSTEM/build.prop")
1063
Tao Baoa3705452019-06-24 15:33:41 -07001064 result = {}
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001065 for codename in codenames:
1066 codename = codename.strip()
Tao Baobadceb22019-03-15 09:33:43 -07001067 if codename:
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001068 result[codename] = api_level
1069 return result
1070
1071
Tao Baoaa7e9932019-03-15 09:37:01 -07001072def ReadApexKeysInfo(tf_zip):
1073 """Parses the APEX keys info from a given target-files zip.
1074
1075 Given a target-files ZipFile, parses the META/apexkeys.txt entry and returns a
1076 dict that contains the mapping from APEX names (e.g. com.android.tzdata) to a
1077 tuple of (payload_key, container_key).
1078
1079 Args:
1080 tf_zip: The input target_files ZipFile (already open).
1081
1082 Returns:
1083 (payload_key, container_key): payload_key contains the path to the payload
1084 signing key; container_key contains the path to the container signing
1085 key.
1086 """
1087 keys = {}
Tao Baoa3705452019-06-24 15:33:41 -07001088 for line in tf_zip.read('META/apexkeys.txt').decode().split('\n'):
Tao Baoaa7e9932019-03-15 09:37:01 -07001089 line = line.strip()
1090 if not line:
1091 continue
1092 matches = re.match(
1093 r'^name="(?P<NAME>.*)"\s+'
1094 r'public_key="(?P<PAYLOAD_PUBLIC_KEY>.*)"\s+'
1095 r'private_key="(?P<PAYLOAD_PRIVATE_KEY>.*)"\s+'
1096 r'container_certificate="(?P<CONTAINER_CERT>.*)"\s+'
Bill Peckham5c7b0342020-04-03 15:36:23 -07001097 r'container_private_key="(?P<CONTAINER_PRIVATE_KEY>.*?)"'
1098 r'(\s+partition="(?P<PARTITION>.*?)")?$',
Tao Baoaa7e9932019-03-15 09:37:01 -07001099 line)
1100 if not matches:
1101 continue
1102
1103 name = matches.group('NAME')
Tao Baoaa7e9932019-03-15 09:37:01 -07001104 payload_private_key = matches.group("PAYLOAD_PRIVATE_KEY")
1105
1106 def CompareKeys(pubkey, pubkey_suffix, privkey, privkey_suffix):
1107 pubkey_suffix_len = len(pubkey_suffix)
1108 privkey_suffix_len = len(privkey_suffix)
1109 return (pubkey.endswith(pubkey_suffix) and
1110 privkey.endswith(privkey_suffix) and
1111 pubkey[:-pubkey_suffix_len] == privkey[:-privkey_suffix_len])
1112
Ivan Lozanob021b2a2020-07-28 09:31:06 -04001113 # Check the container key names, as we'll carry them without the
Tao Bao6d9e3da2019-03-26 12:59:25 -07001114 # extensions. This doesn't apply to payload keys though, which we will use
1115 # full names only.
Tao Baoaa7e9932019-03-15 09:37:01 -07001116 container_cert = matches.group("CONTAINER_CERT")
1117 container_private_key = matches.group("CONTAINER_PRIVATE_KEY")
Tao Baof454c3a2019-04-24 23:53:42 -07001118 if container_cert == 'PRESIGNED' and container_private_key == 'PRESIGNED':
1119 container_key = 'PRESIGNED'
1120 elif CompareKeys(
Tao Baoaa7e9932019-03-15 09:37:01 -07001121 container_cert, OPTIONS.public_key_suffix,
1122 container_private_key, OPTIONS.private_key_suffix):
Tao Baof454c3a2019-04-24 23:53:42 -07001123 container_key = container_cert[:-len(OPTIONS.public_key_suffix)]
1124 else:
Tao Baoaa7e9932019-03-15 09:37:01 -07001125 raise ValueError("Failed to parse container keys: \n{}".format(line))
1126
Tao Baof454c3a2019-04-24 23:53:42 -07001127 keys[name] = (payload_private_key, container_key)
Tao Baoaa7e9932019-03-15 09:37:01 -07001128
1129 return keys
1130
1131
Doug Zongkereef39442009-04-02 12:14:19 -07001132def main(argv):
1133
Doug Zongker831840e2011-09-22 10:28:04 -07001134 key_mapping_options = []
1135
Doug Zongkereef39442009-04-02 12:14:19 -07001136 def option_handler(o, a):
Doug Zongker05d3dea2009-06-22 11:32:31 -07001137 if o in ("-e", "--extra_apks"):
Doug Zongkereef39442009-04-02 12:14:19 -07001138 names, key = a.split("=")
1139 names = names.split(",")
1140 for n in names:
1141 OPTIONS.extra_apks[n] = key
Tao Baoaa7e9932019-03-15 09:37:01 -07001142 elif o == "--extra_apex_payload_key":
1143 apex_name, key = a.split("=")
1144 OPTIONS.extra_apex_payload_keys[apex_name] = key
Tao Bao93c2a012018-06-19 12:19:35 -07001145 elif o == "--skip_apks_with_path_prefix":
Tianjiea85bdf02020-07-29 11:56:19 -07001146 # Check the prefix, which must be in all upper case.
Tao Bao93c2a012018-06-19 12:19:35 -07001147 prefix = a.split('/')[0]
1148 if not prefix or prefix != prefix.upper():
1149 raise ValueError("Invalid path prefix '%s'" % (a,))
1150 OPTIONS.skip_apks_with_path_prefix.add(a)
Doug Zongkereef39442009-04-02 12:14:19 -07001151 elif o in ("-d", "--default_key_mappings"):
Doug Zongker831840e2011-09-22 10:28:04 -07001152 key_mapping_options.append((None, a))
Doug Zongkereef39442009-04-02 12:14:19 -07001153 elif o in ("-k", "--key_mapping"):
Doug Zongker831840e2011-09-22 10:28:04 -07001154 key_mapping_options.append(a.split("=", 1))
Doug Zongker8e931bf2009-04-06 15:21:45 -07001155 elif o in ("-o", "--replace_ota_keys"):
1156 OPTIONS.replace_ota_keys = True
Doug Zongkerae877012009-04-21 10:04:51 -07001157 elif o in ("-t", "--tag_changes"):
1158 new = []
1159 for i in a.split(","):
1160 i = i.strip()
1161 if not i or i[0] not in "-+":
1162 raise ValueError("Bad tag change '%s'" % (i,))
1163 new.append(i[0] + i[1:].strip())
1164 OPTIONS.tag_changes = tuple(new)
Geremy Condraf19b3652014-07-29 17:54:54 -07001165 elif o == "--replace_verity_public_key":
1166 OPTIONS.replace_verity_public_key = (True, a)
1167 elif o == "--replace_verity_private_key":
1168 OPTIONS.replace_verity_private_key = (True, a)
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001169 elif o == "--replace_verity_keyid":
1170 OPTIONS.replace_verity_keyid = (True, a)
Bowgo Tsai2fe786a2020-02-21 17:48:18 +08001171 elif o == "--remove_avb_public_keys":
1172 OPTIONS.remove_avb_public_keys = a.split(",")
Tao Bao639118f2017-06-19 15:48:02 -07001173 elif o == "--avb_vbmeta_key":
1174 OPTIONS.avb_keys['vbmeta'] = a
1175 elif o == "--avb_vbmeta_algorithm":
1176 OPTIONS.avb_algorithms['vbmeta'] = a
1177 elif o == "--avb_vbmeta_extra_args":
1178 OPTIONS.avb_extra_args['vbmeta'] = a
1179 elif o == "--avb_boot_key":
1180 OPTIONS.avb_keys['boot'] = a
1181 elif o == "--avb_boot_algorithm":
1182 OPTIONS.avb_algorithms['boot'] = a
1183 elif o == "--avb_boot_extra_args":
1184 OPTIONS.avb_extra_args['boot'] = a
1185 elif o == "--avb_dtbo_key":
1186 OPTIONS.avb_keys['dtbo'] = a
1187 elif o == "--avb_dtbo_algorithm":
1188 OPTIONS.avb_algorithms['dtbo'] = a
1189 elif o == "--avb_dtbo_extra_args":
1190 OPTIONS.avb_extra_args['dtbo'] = a
1191 elif o == "--avb_system_key":
1192 OPTIONS.avb_keys['system'] = a
1193 elif o == "--avb_system_algorithm":
1194 OPTIONS.avb_algorithms['system'] = a
1195 elif o == "--avb_system_extra_args":
1196 OPTIONS.avb_extra_args['system'] = a
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001197 elif o == "--avb_system_other_key":
1198 OPTIONS.avb_keys['system_other'] = a
1199 elif o == "--avb_system_other_algorithm":
1200 OPTIONS.avb_algorithms['system_other'] = a
1201 elif o == "--avb_system_other_extra_args":
1202 OPTIONS.avb_extra_args['system_other'] = a
Tao Bao639118f2017-06-19 15:48:02 -07001203 elif o == "--avb_vendor_key":
1204 OPTIONS.avb_keys['vendor'] = a
1205 elif o == "--avb_vendor_algorithm":
1206 OPTIONS.avb_algorithms['vendor'] = a
1207 elif o == "--avb_vendor_extra_args":
1208 OPTIONS.avb_extra_args['vendor'] = a
Tao Baod6085d62019-05-06 12:55:42 -07001209 elif o == "--avb_vbmeta_system_key":
1210 OPTIONS.avb_keys['vbmeta_system'] = a
1211 elif o == "--avb_vbmeta_system_algorithm":
1212 OPTIONS.avb_algorithms['vbmeta_system'] = a
1213 elif o == "--avb_vbmeta_system_extra_args":
1214 OPTIONS.avb_extra_args['vbmeta_system'] = a
1215 elif o == "--avb_vbmeta_vendor_key":
1216 OPTIONS.avb_keys['vbmeta_vendor'] = a
1217 elif o == "--avb_vbmeta_vendor_algorithm":
1218 OPTIONS.avb_algorithms['vbmeta_vendor'] = a
1219 elif o == "--avb_vbmeta_vendor_extra_args":
1220 OPTIONS.avb_extra_args['vbmeta_vendor'] = a
Tao Baoaa7e9932019-03-15 09:37:01 -07001221 elif o == "--avb_apex_extra_args":
1222 OPTIONS.avb_extra_args['apex'] = a
Hongguang Chenf23364d2020-04-27 18:36:36 -07001223 elif o == "--avb_extra_custom_image_key":
1224 partition, key = a.split("=")
1225 OPTIONS.avb_keys[partition] = key
1226 elif o == "--avb_extra_custom_image_algorithm":
1227 partition, algorithm = a.split("=")
1228 OPTIONS.avb_algorithms[partition] = algorithm
1229 elif o == "--avb_extra_custom_image_extra_args":
Hongguang Chen883eecb2020-05-23 22:20:19 -07001230 # Setting the maxsplit parameter to one, which will return a list with
1231 # two elements. e.g., the second '=' should not be splitted for
1232 # 'oem=--signing_helper_with_files=/tmp/avbsigner.sh'.
1233 partition, extra_args = a.split("=", 1)
Hongguang Chenf23364d2020-04-27 18:36:36 -07001234 OPTIONS.avb_extra_args[partition] = extra_args
Doug Zongkereef39442009-04-02 12:14:19 -07001235 else:
1236 return False
1237 return True
1238
Tao Bao639118f2017-06-19 15:48:02 -07001239 args = common.ParseOptions(
1240 argv, __doc__,
1241 extra_opts="e:d:k:ot:",
1242 extra_long_opts=[
Tao Bao0c28d2d2017-12-24 10:37:38 -08001243 "extra_apks=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001244 "extra_apex_payload_key=",
Tao Bao93c2a012018-06-19 12:19:35 -07001245 "skip_apks_with_path_prefix=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001246 "default_key_mappings=",
1247 "key_mapping=",
1248 "replace_ota_keys",
1249 "tag_changes=",
1250 "replace_verity_public_key=",
1251 "replace_verity_private_key=",
1252 "replace_verity_keyid=",
Bowgo Tsai2fe786a2020-02-21 17:48:18 +08001253 "remove_avb_public_keys=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001254 "avb_apex_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001255 "avb_vbmeta_algorithm=",
1256 "avb_vbmeta_key=",
1257 "avb_vbmeta_extra_args=",
1258 "avb_boot_algorithm=",
1259 "avb_boot_key=",
1260 "avb_boot_extra_args=",
1261 "avb_dtbo_algorithm=",
1262 "avb_dtbo_key=",
1263 "avb_dtbo_extra_args=",
1264 "avb_system_algorithm=",
1265 "avb_system_key=",
1266 "avb_system_extra_args=",
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001267 "avb_system_other_algorithm=",
1268 "avb_system_other_key=",
1269 "avb_system_other_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001270 "avb_vendor_algorithm=",
1271 "avb_vendor_key=",
1272 "avb_vendor_extra_args=",
Tao Baod6085d62019-05-06 12:55:42 -07001273 "avb_vbmeta_system_algorithm=",
1274 "avb_vbmeta_system_key=",
1275 "avb_vbmeta_system_extra_args=",
1276 "avb_vbmeta_vendor_algorithm=",
1277 "avb_vbmeta_vendor_key=",
1278 "avb_vbmeta_vendor_extra_args=",
Hongguang Chenf23364d2020-04-27 18:36:36 -07001279 "avb_extra_custom_image_key=",
1280 "avb_extra_custom_image_algorithm=",
1281 "avb_extra_custom_image_extra_args=",
Tao Bao639118f2017-06-19 15:48:02 -07001282 ],
1283 extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001284
1285 if len(args) != 2:
1286 common.Usage(__doc__)
1287 sys.exit(1)
1288
Tao Baobadceb22019-03-15 09:33:43 -07001289 common.InitLogging()
1290
Kelvin Zhang928c2342020-09-22 16:15:57 -04001291 input_zip = zipfile.ZipFile(args[0], "r", allowZip64=True)
Tao Bao2b8f4892017-06-13 12:54:58 -07001292 output_zip = zipfile.ZipFile(args[1], "w",
1293 compression=zipfile.ZIP_DEFLATED,
1294 allowZip64=True)
Doug Zongkereef39442009-04-02 12:14:19 -07001295
Doug Zongker831840e2011-09-22 10:28:04 -07001296 misc_info = common.LoadInfoDict(input_zip)
1297
1298 BuildKeyMap(misc_info, key_mapping_options)
1299
Tao Baoaa7e9932019-03-15 09:37:01 -07001300 apk_keys_info, compressed_extension = common.ReadApkCerts(input_zip)
1301 apk_keys = GetApkCerts(apk_keys_info)
Doug Zongkereb338ef2009-05-20 16:50:49 -07001302
Tao Baoaa7e9932019-03-15 09:37:01 -07001303 apex_keys_info = ReadApexKeysInfo(input_zip)
1304 apex_keys = GetApexKeys(apex_keys_info, apk_keys)
1305
Tianjie Xu88a759d2020-01-23 10:47:54 -08001306 # TODO(xunchang) check for the apks inside the apex files, and abort early if
1307 # the keys are not available.
Tao Baoaa7e9932019-03-15 09:37:01 -07001308 CheckApkAndApexKeysAvailable(
1309 input_zip,
1310 set(apk_keys.keys()) | set(apex_keys.keys()),
Tao Baoe1343992019-03-19 12:24:03 -07001311 compressed_extension,
1312 apex_keys)
Tao Baoaa7e9932019-03-15 09:37:01 -07001313
1314 key_passwords = common.GetKeyPasswords(
1315 set(apk_keys.values()) | set(itertools.chain(*apex_keys.values())))
Tao Bao9aa4b9b2016-09-29 17:53:56 -07001316 platform_api_level, _ = GetApiLevelAndCodename(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001317 codename_to_api_level_map = GetCodenameToApiLevelMap(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001318
Doug Zongker412c02f2014-02-13 10:58:24 -08001319 ProcessTargetFiles(input_zip, output_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -07001320 apk_keys, apex_keys, key_passwords,
1321 platform_api_level, codename_to_api_level_map,
Narayan Kamatha07bf042017-08-14 14:49:21 +01001322 compressed_extension)
Doug Zongker8e931bf2009-04-06 15:21:45 -07001323
Tao Bao2ed665a2015-04-01 11:21:55 -07001324 common.ZipClose(input_zip)
1325 common.ZipClose(output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001326
Tianjie Xub48589a2016-08-03 19:21:52 -07001327 # Skip building userdata.img and cache.img when signing the target files.
Tianjie Xu616fbeb2017-05-23 14:51:02 -07001328 new_args = ["--is_signing"]
1329 # add_img_to_target_files builds the system image from scratch, so the
1330 # recovery patch is guaranteed to be regenerated there.
1331 if OPTIONS.rebuild_recovery:
1332 new_args.append("--rebuild_recovery")
1333 new_args.append(args[1])
Tianjie Xub48589a2016-08-03 19:21:52 -07001334 add_img_to_target_files.main(new_args)
Doug Zongker3c84f562014-07-31 11:06:30 -07001335
Tao Bao0c28d2d2017-12-24 10:37:38 -08001336 print("done.")
Doug Zongkereef39442009-04-02 12:14:19 -07001337
1338
1339if __name__ == '__main__':
1340 try:
1341 main(sys.argv[1:])
Tao Bao0c28d2d2017-12-24 10:37:38 -08001342 except common.ExternalError as e:
1343 print("\n ERROR: %s\n" % (e,))
Doug Zongkereef39442009-04-02 12:14:19 -07001344 sys.exit(1)
Tao Bao639118f2017-06-19 15:48:02 -07001345 finally:
1346 common.Cleanup()