blob: 5b7c2ac676a085775a37770b7ef2218dfb66f4fc [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
115 --android_jar_path <path>
116 Path to the android.jar to repack the apex file.
Doug Zongkereef39442009-04-02 12:14:19 -0700117"""
118
Tao Bao0c28d2d2017-12-24 10:37:38 -0800119from __future__ import print_function
Doug Zongkereef39442009-04-02 12:14:19 -0700120
Robert Craig817c5742013-04-19 10:59:22 -0400121import base64
Doug Zongker8e931bf2009-04-06 15:21:45 -0700122import copy
Robert Craig817c5742013-04-19 10:59:22 -0400123import errno
Narayan Kamatha07bf042017-08-14 14:49:21 +0100124import gzip
Tao Baobb733882019-07-24 23:31:19 -0700125import io
Tao Baoaa7e9932019-03-15 09:37:01 -0700126import itertools
Tao Baobadceb22019-03-15 09:33:43 -0700127import logging
Doug Zongkereef39442009-04-02 12:14:19 -0700128import os
129import re
Narayan Kamatha07bf042017-08-14 14:49:21 +0100130import shutil
Tao Bao9fdd00f2017-07-12 11:57:05 -0700131import stat
Doug Zongkereef39442009-04-02 12:14:19 -0700132import subprocess
Tao Bao0c28d2d2017-12-24 10:37:38 -0800133import sys
Doug Zongkereef39442009-04-02 12:14:19 -0700134import tempfile
135import zipfile
Tao Bao66472632017-12-04 17:16:36 -0800136from xml.etree import ElementTree
Doug Zongkereef39442009-04-02 12:14:19 -0700137
Doug Zongker3c84f562014-07-31 11:06:30 -0700138import add_img_to_target_files
Tao Baoaa7e9932019-03-15 09:37:01 -0700139import apex_utils
Doug Zongkereef39442009-04-02 12:14:19 -0700140import common
141
Tao Bao0c28d2d2017-12-24 10:37:38 -0800142
143if sys.hexversion < 0x02070000:
144 print("Python 2.7 or newer is required.", file=sys.stderr)
145 sys.exit(1)
146
147
Tao Baobadceb22019-03-15 09:33:43 -0700148logger = logging.getLogger(__name__)
149
Doug Zongkereef39442009-04-02 12:14:19 -0700150OPTIONS = common.OPTIONS
151
152OPTIONS.extra_apks = {}
Tao Baoaa7e9932019-03-15 09:37:01 -0700153OPTIONS.extra_apex_payload_keys = {}
Tao Bao93c2a012018-06-19 12:19:35 -0700154OPTIONS.skip_apks_with_path_prefix = set()
Doug Zongkereef39442009-04-02 12:14:19 -0700155OPTIONS.key_map = {}
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700156OPTIONS.rebuild_recovery = False
Doug Zongker8e931bf2009-04-06 15:21:45 -0700157OPTIONS.replace_ota_keys = False
Geremy Condraf19b3652014-07-29 17:54:54 -0700158OPTIONS.replace_verity_public_key = False
159OPTIONS.replace_verity_private_key = False
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700160OPTIONS.replace_verity_keyid = False
Bowgo Tsai2fe786a2020-02-21 17:48:18 +0800161OPTIONS.remove_avb_public_keys = None
Doug Zongker831840e2011-09-22 10:28:04 -0700162OPTIONS.tag_changes = ("-test-keys", "-dev-keys", "+release-keys")
Tao Bao639118f2017-06-19 15:48:02 -0700163OPTIONS.avb_keys = {}
164OPTIONS.avb_algorithms = {}
165OPTIONS.avb_extra_args = {}
Tianjie Xu88a759d2020-01-23 10:47:54 -0800166OPTIONS.android_jar_path = None
Doug Zongkereef39442009-04-02 12:14:19 -0700167
Tao Bao0c28d2d2017-12-24 10:37:38 -0800168
Tao Bao19b02fe2019-10-09 00:04:28 -0700169AVB_FOOTER_ARGS_BY_PARTITION = {
170 'boot' : 'avb_boot_add_hash_footer_args',
171 'dtbo' : 'avb_dtbo_add_hash_footer_args',
172 'recovery' : 'avb_recovery_add_hash_footer_args',
173 'system' : 'avb_system_add_hashtree_footer_args',
174 'system_other' : 'avb_system_other_add_hashtree_footer_args',
175 'vendor' : 'avb_vendor_add_hashtree_footer_args',
176 'vendor_boot' : 'avb_vendor_boot_add_hash_footer_args',
177 'vbmeta' : 'avb_vbmeta_args',
178 'vbmeta_system' : 'avb_vbmeta_system_args',
179 'vbmeta_vendor' : 'avb_vbmeta_vendor_args',
180}
181
182
Narayan Kamatha07bf042017-08-14 14:49:21 +0100183def GetApkCerts(certmap):
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800184 # apply the key remapping to the contents of the file
Tao Baoa3705452019-06-24 15:33:41 -0700185 for apk, cert in certmap.items():
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800186 certmap[apk] = OPTIONS.key_map.get(cert, cert)
187
188 # apply all the -e options, overriding anything in the file
Tao Baoa3705452019-06-24 15:33:41 -0700189 for apk, cert in OPTIONS.extra_apks.items():
Doug Zongkerdecf9952009-12-15 17:27:49 -0800190 if not cert:
191 cert = "PRESIGNED"
Doug Zongkerad88c7c2009-04-14 12:34:27 -0700192 certmap[apk] = OPTIONS.key_map.get(cert, cert)
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800193
Doug Zongkereef39442009-04-02 12:14:19 -0700194 return certmap
195
196
Tao Baoaa7e9932019-03-15 09:37:01 -0700197def GetApexKeys(keys_info, key_map):
198 """Gets APEX payload and container signing keys by applying the mapping rules.
199
Tao Baoe1343992019-03-19 12:24:03 -0700200 Presigned payload / container keys will be set accordingly.
Tao Baoaa7e9932019-03-15 09:37:01 -0700201
202 Args:
203 keys_info: A dict that maps from APEX filenames to a tuple of (payload_key,
204 container_key).
205 key_map: A dict that overrides the keys, specified via command-line input.
206
207 Returns:
208 A dict that contains the updated APEX key mapping, which should be used for
209 the current signing.
Tao Baof98fa102019-04-24 14:51:25 -0700210
211 Raises:
212 AssertionError: On invalid container / payload key overrides.
Tao Baoaa7e9932019-03-15 09:37:01 -0700213 """
214 # Apply all the --extra_apex_payload_key options to override the payload
215 # signing keys in the given keys_info.
216 for apex, key in OPTIONS.extra_apex_payload_keys.items():
Tao Baoe1343992019-03-19 12:24:03 -0700217 if not key:
218 key = 'PRESIGNED'
Tao Bao34223092019-07-11 11:52:52 -0700219 if apex not in keys_info:
220 logger.warning('Failed to find %s in target_files; Ignored', apex)
221 continue
Tao Baoaa7e9932019-03-15 09:37:01 -0700222 keys_info[apex] = (key, keys_info[apex][1])
223
224 # Apply the key remapping to container keys.
225 for apex, (payload_key, container_key) in keys_info.items():
226 keys_info[apex] = (payload_key, key_map.get(container_key, container_key))
227
228 # Apply all the --extra_apks options to override the container keys.
229 for apex, key in OPTIONS.extra_apks.items():
230 # Skip non-APEX containers.
231 if apex not in keys_info:
232 continue
Tao Baoe1343992019-03-19 12:24:03 -0700233 if not key:
234 key = 'PRESIGNED'
Tao Baofa9de0a2019-03-18 10:24:17 -0700235 keys_info[apex] = (keys_info[apex][0], key_map.get(key, key))
Tao Baoaa7e9932019-03-15 09:37:01 -0700236
Tao Baof98fa102019-04-24 14:51:25 -0700237 # A PRESIGNED container entails a PRESIGNED payload. Apply this to all the
238 # APEX key pairs. However, a PRESIGNED container with non-PRESIGNED payload
239 # (overridden via commandline) indicates a config error, which should not be
240 # allowed.
241 for apex, (payload_key, container_key) in keys_info.items():
242 if container_key != 'PRESIGNED':
243 continue
244 if apex in OPTIONS.extra_apex_payload_keys:
245 payload_override = OPTIONS.extra_apex_payload_keys[apex]
246 assert payload_override == '', \
247 ("Invalid APEX key overrides: {} has PRESIGNED container but "
248 "non-PRESIGNED payload key {}").format(apex, payload_override)
249 if payload_key != 'PRESIGNED':
250 print(
251 "Setting {} payload as PRESIGNED due to PRESIGNED container".format(
252 apex))
253 keys_info[apex] = ('PRESIGNED', 'PRESIGNED')
254
Tao Baoaa7e9932019-03-15 09:37:01 -0700255 return keys_info
256
257
Tao Bao93c2a012018-06-19 12:19:35 -0700258def GetApkFileInfo(filename, compressed_extension, skipped_prefixes):
Tao Bao11f955c2018-06-19 12:19:35 -0700259 """Returns the APK info based on the given filename.
260
261 Checks if the given filename (with path) looks like an APK file, by taking the
Tao Bao93c2a012018-06-19 12:19:35 -0700262 compressed extension into consideration. If it appears to be an APK file,
263 further checks if the APK file should be skipped when signing, based on the
264 given path prefixes.
Tao Bao11f955c2018-06-19 12:19:35 -0700265
266 Args:
267 filename: Path to the file.
268 compressed_extension: The extension string of compressed APKs (e.g. ".gz"),
269 or None if there's no compressed APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700270 skipped_prefixes: A set/list/tuple of the path prefixes to be skipped.
Tao Bao11f955c2018-06-19 12:19:35 -0700271
272 Returns:
Tao Bao93c2a012018-06-19 12:19:35 -0700273 (is_apk, is_compressed, should_be_skipped): is_apk indicates whether the
274 given filename is an APK file. is_compressed indicates whether the APK file
275 is compressed (only meaningful when is_apk is True). should_be_skipped
276 indicates whether the filename matches any of the given prefixes to be
277 skipped.
Tao Bao11f955c2018-06-19 12:19:35 -0700278
279 Raises:
Tao Bao93c2a012018-06-19 12:19:35 -0700280 AssertionError: On invalid compressed_extension or skipped_prefixes inputs.
Tao Bao11f955c2018-06-19 12:19:35 -0700281 """
282 assert compressed_extension is None or compressed_extension.startswith('.'), \
283 "Invalid compressed_extension arg: '{}'".format(compressed_extension)
284
Tao Bao93c2a012018-06-19 12:19:35 -0700285 # skipped_prefixes should be one of set/list/tuple types. Other types such as
286 # str shouldn't be accepted.
Tao Baobadceb22019-03-15 09:33:43 -0700287 assert isinstance(skipped_prefixes, (set, list, tuple)), \
288 "Invalid skipped_prefixes input type: {}".format(type(skipped_prefixes))
Tao Bao93c2a012018-06-19 12:19:35 -0700289
Tao Bao11f955c2018-06-19 12:19:35 -0700290 compressed_apk_extension = (
291 ".apk" + compressed_extension if compressed_extension else None)
292 is_apk = (filename.endswith(".apk") or
293 (compressed_apk_extension and
294 filename.endswith(compressed_apk_extension)))
295 if not is_apk:
Tao Bao93c2a012018-06-19 12:19:35 -0700296 return (False, False, False)
Tao Bao11f955c2018-06-19 12:19:35 -0700297
298 is_compressed = (compressed_apk_extension and
299 filename.endswith(compressed_apk_extension))
Tao Bao93c2a012018-06-19 12:19:35 -0700300 should_be_skipped = filename.startswith(tuple(skipped_prefixes))
301 return (True, is_compressed, should_be_skipped)
Tao Bao11f955c2018-06-19 12:19:35 -0700302
303
Tao Baoaa7e9932019-03-15 09:37:01 -0700304def CheckApkAndApexKeysAvailable(input_tf_zip, known_keys,
Tao Baoe1343992019-03-19 12:24:03 -0700305 compressed_extension, apex_keys):
Tao Baoaa7e9932019-03-15 09:37:01 -0700306 """Checks that all the APKs and APEXes have keys specified.
Tao Bao11f955c2018-06-19 12:19:35 -0700307
308 Args:
309 input_tf_zip: An open target_files zip file.
Tao Baoaa7e9932019-03-15 09:37:01 -0700310 known_keys: A set of APKs and APEXes that have known signing keys.
Tao Bao11f955c2018-06-19 12:19:35 -0700311 compressed_extension: The extension string of compressed APKs, such as
Tao Baoaa7e9932019-03-15 09:37:01 -0700312 '.gz', or None if there's no compressed APKs.
Tao Baoe1343992019-03-19 12:24:03 -0700313 apex_keys: A dict that contains the key mapping from APEX name to
314 (payload_key, container_key).
Tao Bao11f955c2018-06-19 12:19:35 -0700315
316 Raises:
Tao Baoaa7e9932019-03-15 09:37:01 -0700317 AssertionError: On finding unknown APKs and APEXes.
Tao Bao11f955c2018-06-19 12:19:35 -0700318 """
Tao Baoaa7e9932019-03-15 09:37:01 -0700319 unknown_files = []
Doug Zongkereb338ef2009-05-20 16:50:49 -0700320 for info in input_tf_zip.infolist():
Tao Baoaa7e9932019-03-15 09:37:01 -0700321 # Handle APEXes first, e.g. SYSTEM/apex/com.android.tzdata.apex.
322 if (info.filename.startswith('SYSTEM/apex') and
323 info.filename.endswith('.apex')):
324 name = os.path.basename(info.filename)
325 if name not in known_keys:
326 unknown_files.append(name)
327 continue
328
329 # And APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700330 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
331 info.filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
332 if not is_apk or should_be_skipped:
Tao Bao11f955c2018-06-19 12:19:35 -0700333 continue
Tao Baoaa7e9932019-03-15 09:37:01 -0700334
Tao Bao11f955c2018-06-19 12:19:35 -0700335 name = os.path.basename(info.filename)
336 if is_compressed:
337 name = name[:-len(compressed_extension)]
Tao Baoaa7e9932019-03-15 09:37:01 -0700338 if name not in known_keys:
339 unknown_files.append(name)
Tao Bao11f955c2018-06-19 12:19:35 -0700340
Tao Baoaa7e9932019-03-15 09:37:01 -0700341 assert not unknown_files, \
Tao Bao11f955c2018-06-19 12:19:35 -0700342 ("No key specified for:\n {}\n"
343 "Use '-e <apkname>=' to specify a key (which may be an empty string to "
Tao Baoaa7e9932019-03-15 09:37:01 -0700344 "not sign this apk).".format("\n ".join(unknown_files)))
Doug Zongkereb338ef2009-05-20 16:50:49 -0700345
Tao Baoe1343992019-03-19 12:24:03 -0700346 # For all the APEXes, double check that we won't have an APEX that has only
Tao Baof98fa102019-04-24 14:51:25 -0700347 # one of the payload / container keys set. Note that non-PRESIGNED container
348 # with PRESIGNED payload could be allowed but currently unsupported. It would
349 # require changing SignApex implementation.
Tao Baoe1343992019-03-19 12:24:03 -0700350 if not apex_keys:
351 return
352
353 invalid_apexes = []
354 for info in input_tf_zip.infolist():
355 if (not info.filename.startswith('SYSTEM/apex') or
356 not info.filename.endswith('.apex')):
357 continue
358
359 name = os.path.basename(info.filename)
360 (payload_key, container_key) = apex_keys[name]
361 if ((payload_key in common.SPECIAL_CERT_STRINGS and
362 container_key not in common.SPECIAL_CERT_STRINGS) or
363 (payload_key not in common.SPECIAL_CERT_STRINGS and
364 container_key in common.SPECIAL_CERT_STRINGS)):
365 invalid_apexes.append(
366 "{}: payload_key {}, container_key {}".format(
367 name, payload_key, container_key))
368
369 assert not invalid_apexes, \
370 "Invalid APEX keys specified:\n {}\n".format(
371 "\n ".join(invalid_apexes))
372
Doug Zongkereb338ef2009-05-20 16:50:49 -0700373
Narayan Kamatha07bf042017-08-14 14:49:21 +0100374def SignApk(data, keyname, pw, platform_api_level, codename_to_api_level_map,
375 is_compressed):
Doug Zongkereef39442009-04-02 12:14:19 -0700376 unsigned = tempfile.NamedTemporaryFile()
377 unsigned.write(data)
378 unsigned.flush()
379
Narayan Kamatha07bf042017-08-14 14:49:21 +0100380 if is_compressed:
381 uncompressed = tempfile.NamedTemporaryFile()
Tao Bao0c28d2d2017-12-24 10:37:38 -0800382 with gzip.open(unsigned.name, "rb") as in_file, \
383 open(uncompressed.name, "wb") as out_file:
Narayan Kamatha07bf042017-08-14 14:49:21 +0100384 shutil.copyfileobj(in_file, out_file)
385
386 # Finally, close the "unsigned" file (which is gzip compressed), and then
387 # replace it with the uncompressed version.
388 #
389 # TODO(narayan): All this nastiness can be avoided if python 3.2 is in use,
390 # we could just gzip / gunzip in-memory buffers instead.
391 unsigned.close()
392 unsigned = uncompressed
393
Doug Zongkereef39442009-04-02 12:14:19 -0700394 signed = tempfile.NamedTemporaryFile()
395
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800396 # For pre-N builds, don't upgrade to SHA-256 JAR signatures based on the APK's
397 # minSdkVersion to avoid increasing incremental OTA update sizes. If an APK
398 # didn't change, we don't want its signature to change due to the switch
399 # from SHA-1 to SHA-256.
400 # By default, APK signer chooses SHA-256 signatures if the APK's minSdkVersion
401 # is 18 or higher. For pre-N builds we disable this mechanism by pretending
402 # that the APK's minSdkVersion is 1.
403 # For N+ builds, we let APK signer rely on the APK's minSdkVersion to
404 # determine whether to use SHA-256.
405 min_api_level = None
406 if platform_api_level > 23:
407 # Let APK signer choose whether to use SHA-1 or SHA-256, based on the APK's
408 # minSdkVersion attribute
409 min_api_level = None
410 else:
411 # Force APK signer to use SHA-1
412 min_api_level = 1
413
414 common.SignFile(unsigned.name, signed.name, keyname, pw,
Tao Bao0c28d2d2017-12-24 10:37:38 -0800415 min_api_level=min_api_level,
416 codename_to_api_level_map=codename_to_api_level_map)
Doug Zongkereef39442009-04-02 12:14:19 -0700417
Tao Bao0c28d2d2017-12-24 10:37:38 -0800418 data = None
Narayan Kamatha07bf042017-08-14 14:49:21 +0100419 if is_compressed:
420 # Recompress the file after it has been signed.
421 compressed = tempfile.NamedTemporaryFile()
Tao Bao0c28d2d2017-12-24 10:37:38 -0800422 with open(signed.name, "rb") as in_file, \
423 gzip.open(compressed.name, "wb") as out_file:
Narayan Kamatha07bf042017-08-14 14:49:21 +0100424 shutil.copyfileobj(in_file, out_file)
425
426 data = compressed.read()
427 compressed.close()
428 else:
429 data = signed.read()
430
Doug Zongkereef39442009-04-02 12:14:19 -0700431 unsigned.close()
432 signed.close()
433
434 return data
435
436
Doug Zongker412c02f2014-02-13 10:58:24 -0800437def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -0700438 apk_keys, apex_keys, key_passwords,
439 platform_api_level, codename_to_api_level_map,
Narayan Kamatha07bf042017-08-14 14:49:21 +0100440 compressed_extension):
Tao Bao93c2a012018-06-19 12:19:35 -0700441 # maxsize measures the maximum filename length, including the ones to be
442 # skipped.
Tao Bao0c28d2d2017-12-24 10:37:38 -0800443 maxsize = max(
444 [len(os.path.basename(i.filename)) for i in input_tf_zip.infolist()
Tao Bao93c2a012018-06-19 12:19:35 -0700445 if GetApkFileInfo(i.filename, compressed_extension, [])[0]])
Tao Baoa80ed222016-06-16 14:41:24 -0700446 system_root_image = misc_info.get("system_root_image") == "true"
Doug Zongker412c02f2014-02-13 10:58:24 -0800447
Doug Zongkereef39442009-04-02 12:14:19 -0700448 for info in input_tf_zip.infolist():
Tao Bao11f955c2018-06-19 12:19:35 -0700449 filename = info.filename
450 if filename.startswith("IMAGES/"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700451 continue
Doug Zongker3c84f562014-07-31 11:06:30 -0700452
Tao Bao04808502019-07-25 23:11:41 -0700453 # Skip OTA-specific images (e.g. split super images), which will be
454 # re-generated during signing.
Tao Bao33bf2682019-01-11 12:37:35 -0800455 if filename.startswith("OTA/") and filename.endswith(".img"):
456 continue
457
Tao Bao11f955c2018-06-19 12:19:35 -0700458 data = input_tf_zip.read(filename)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700459 out_info = copy.copy(info)
Tao Bao93c2a012018-06-19 12:19:35 -0700460 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
461 filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
462
463 if is_apk and should_be_skipped:
464 # Copy skipped APKs verbatim.
465 print(
466 "NOT signing: %s\n"
467 " (skipped due to matching prefix)" % (filename,))
468 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker412c02f2014-02-13 10:58:24 -0800469
Tao Baof2cffbd2015-07-22 12:33:18 -0700470 # Sign APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700471 elif is_apk:
Tao Bao11f955c2018-06-19 12:19:35 -0700472 name = os.path.basename(filename)
Narayan Kamatha07bf042017-08-14 14:49:21 +0100473 if is_compressed:
474 name = name[:-len(compressed_extension)]
475
Tao Baoaa7e9932019-03-15 09:37:01 -0700476 key = apk_keys[name]
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800477 if key not in common.SPECIAL_CERT_STRINGS:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800478 print(" signing: %-*s (%s)" % (maxsize, name, key))
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800479 signed_data = SignApk(data, key, key_passwords[key], platform_api_level,
Tao Bao0c28d2d2017-12-24 10:37:38 -0800480 codename_to_api_level_map, is_compressed)
Tao Bao2ed665a2015-04-01 11:21:55 -0700481 common.ZipWriteStr(output_tf_zip, out_info, signed_data)
Doug Zongkereef39442009-04-02 12:14:19 -0700482 else:
483 # an APK we're not supposed to sign.
Tao Bao93c2a012018-06-19 12:19:35 -0700484 print(
485 "NOT signing: %s\n"
486 " (skipped due to special cert string)" % (name,))
Tao Bao2ed665a2015-04-01 11:21:55 -0700487 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoa80ed222016-06-16 14:41:24 -0700488
Tao Baoaa7e9932019-03-15 09:37:01 -0700489 # Sign bundled APEX files.
490 elif filename.startswith("SYSTEM/apex") and filename.endswith(".apex"):
491 name = os.path.basename(filename)
492 payload_key, container_key = apex_keys[name]
493
Tao Baoe1343992019-03-19 12:24:03 -0700494 # We've asserted not having a case with only one of them PRESIGNED.
495 if (payload_key not in common.SPECIAL_CERT_STRINGS and
496 container_key not in common.SPECIAL_CERT_STRINGS):
497 print(" signing: %-*s container (%s)" % (
498 maxsize, name, container_key))
499 print(" : %-*s payload (%s)" % (
500 maxsize, name, payload_key))
Tao Baoaa7e9932019-03-15 09:37:01 -0700501
Tao Baoe7354ba2019-05-09 16:54:15 -0700502 signed_apex = apex_utils.SignApex(
Tao Bao1ac886e2019-06-26 11:58:22 -0700503 misc_info['avb_avbtool'],
Tao Baoe1343992019-03-19 12:24:03 -0700504 data,
505 payload_key,
506 container_key,
507 key_passwords[container_key],
Tianjie Xu88a759d2020-01-23 10:47:54 -0800508 apk_keys,
Tao Baoe1343992019-03-19 12:24:03 -0700509 codename_to_api_level_map,
Tao Bao448004a2019-09-19 07:55:02 -0700510 no_hashtree=True,
511 signing_args=OPTIONS.avb_extra_args.get('apex'))
Tao Baoe1343992019-03-19 12:24:03 -0700512 common.ZipWrite(output_tf_zip, signed_apex, filename)
Tao Baoaa7e9932019-03-15 09:37:01 -0700513
Tao Baoe1343992019-03-19 12:24:03 -0700514 else:
515 print(
516 "NOT signing: %s\n"
517 " (skipped due to special cert string)" % (name,))
518 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoaa7e9932019-03-15 09:37:01 -0700519
520 # AVB public keys for the installed APEXes, which will be updated later.
521 elif (os.path.dirname(filename) == 'SYSTEM/etc/security/apex' and
522 filename != 'SYSTEM/etc/security/apex/'):
523 continue
524
Tao Baoa80ed222016-06-16 14:41:24 -0700525 # System properties.
Tao Bao338c1b72019-06-21 09:38:24 -0700526 elif filename in (
527 "SYSTEM/build.prop",
528
529 "VENDOR/build.prop",
530 "SYSTEM/vendor/build.prop",
531
532 "ODM/etc/build.prop",
533 "VENDOR/odm/etc/build.prop",
534
535 "PRODUCT/build.prop",
536 "SYSTEM/product/build.prop",
537
Justin Yun6151e3f2019-06-25 15:58:13 +0900538 "SYSTEM_EXT/build.prop",
539 "SYSTEM/system_ext/build.prop",
Tao Bao338c1b72019-06-21 09:38:24 -0700540
541 "SYSTEM/etc/prop.default",
542 "BOOT/RAMDISK/prop.default",
543 "RECOVERY/RAMDISK/prop.default",
544
545 # ROOT/default.prop is a legacy path, but may still exist for upgrading
546 # devices that don't support `property_overrides_split_enabled`.
547 "ROOT/default.prop",
548
549 # RECOVERY/RAMDISK/default.prop is a legacy path, but will always exist
550 # as a symlink in the current code. So it's a no-op here. Keeping the
551 # path here for clarity.
552 "RECOVERY/RAMDISK/default.prop"):
Tao Bao11f955c2018-06-19 12:19:35 -0700553 print("Rewriting %s:" % (filename,))
Hung-ying Tyan7eb6a922017-05-01 21:56:26 +0800554 if stat.S_ISLNK(info.external_attr >> 16):
555 new_data = data
556 else:
Tao Baoa3705452019-06-24 15:33:41 -0700557 new_data = RewriteProps(data.decode())
Tao Bao2ed665a2015-04-01 11:21:55 -0700558 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700559
Tao Bao66472632017-12-04 17:16:36 -0800560 # Replace the certs in *mac_permissions.xml (there could be multiple, such
561 # as {system,vendor}/etc/selinux/{plat,nonplat}_mac_permissions.xml).
Tao Bao11f955c2018-06-19 12:19:35 -0700562 elif filename.endswith("mac_permissions.xml"):
563 print("Rewriting %s with new keys." % (filename,))
Tao Baoa3705452019-06-24 15:33:41 -0700564 new_data = ReplaceCerts(data.decode())
Tao Bao2ed665a2015-04-01 11:21:55 -0700565 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700566
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700567 # Ask add_img_to_target_files to rebuild the recovery patch if needed.
Tao Bao11f955c2018-06-19 12:19:35 -0700568 elif filename in ("SYSTEM/recovery-from-boot.p",
Robin Leeda427de2020-01-03 19:16:32 +0100569 "VENDOR/recovery-from-boot.p",
570
Tao Bao11f955c2018-06-19 12:19:35 -0700571 "SYSTEM/etc/recovery.img",
Robin Leeda427de2020-01-03 19:16:32 +0100572 "VENDOR/etc/recovery.img",
573
574 "SYSTEM/bin/install-recovery.sh",
575 "VENDOR/bin/install-recovery.sh"):
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700576 OPTIONS.rebuild_recovery = True
Tao Baoa80ed222016-06-16 14:41:24 -0700577
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700578 # Don't copy OTA certs if we're replacing them.
Tianjie Xu2df23d72019-10-15 18:06:25 -0700579 # Replacement of update-payload-key.pub.pem was removed in b/116660991.
Tao Bao696bb332018-08-17 16:27:01 -0700580 elif (
581 OPTIONS.replace_ota_keys and
582 filename in (
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700583 "BOOT/RAMDISK/system/etc/security/otacerts.zip",
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700584 "RECOVERY/RAMDISK/system/etc/security/otacerts.zip",
Tianjie Xu2df23d72019-10-15 18:06:25 -0700585 "SYSTEM/etc/security/otacerts.zip")):
Doug Zongker412c02f2014-02-13 10:58:24 -0800586 pass
Tao Baoa80ed222016-06-16 14:41:24 -0700587
Tao Bao46a59992017-06-05 11:55:16 -0700588 # Skip META/misc_info.txt since we will write back the new values later.
Tao Bao11f955c2018-06-19 12:19:35 -0700589 elif filename == "META/misc_info.txt":
Geremy Condraf19b3652014-07-29 17:54:54 -0700590 pass
Tao Bao8adcfd12016-06-17 17:01:22 -0700591
592 # Skip verity public key if we will replace it.
Michael Runge947894f2014-10-14 20:58:38 -0700593 elif (OPTIONS.replace_verity_public_key and
Tao Bao11f955c2018-06-19 12:19:35 -0700594 filename in ("BOOT/RAMDISK/verity_key",
595 "ROOT/verity_key")):
Geremy Condraf19b3652014-07-29 17:54:54 -0700596 pass
Bowgo Tsai2fe786a2020-02-21 17:48:18 +0800597 elif (OPTIONS.remove_avb_public_keys and
598 (filename.startswith("BOOT/RAMDISK/avb/") or
599 filename.startswith("BOOT/RAMDISK/first_stage_ramdisk/avb/"))):
600 matched_removal = False
601 for key_to_remove in OPTIONS.remove_avb_public_keys:
602 if filename.endswith(key_to_remove):
603 matched_removal = True
604 print("Removing AVB public key from ramdisk: %s" % filename)
605 break
606 if not matched_removal:
607 # Copy it verbatim if we don't want to remove it.
608 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoa80ed222016-06-16 14:41:24 -0700609
Tao Bao8adcfd12016-06-17 17:01:22 -0700610 # Skip verity keyid (for system_root_image use) if we will replace it.
Tao Bao11f955c2018-06-19 12:19:35 -0700611 elif OPTIONS.replace_verity_keyid and filename == "BOOT/cmdline":
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700612 pass
613
Tianjie Xu4f099002016-08-11 18:04:27 -0700614 # Skip the care_map as we will regenerate the system/vendor images.
Tianjie Xu4c05f4a2018-09-14 16:24:41 -0700615 elif filename == "META/care_map.pb" or filename == "META/care_map.txt":
Tianjie Xu4f099002016-08-11 18:04:27 -0700616 pass
617
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800618 # Updates system_other.avbpubkey in /product/etc/.
619 elif filename in (
620 "PRODUCT/etc/security/avb/system_other.avbpubkey",
621 "SYSTEM/product/etc/security/avb/system_other.avbpubkey"):
622 # Only update system_other's public key, if the corresponding signing
623 # key is specified via --avb_system_other_key.
624 signing_key = OPTIONS.avb_keys.get("system_other")
625 if signing_key:
Tao Bao1ac886e2019-06-26 11:58:22 -0700626 public_key = common.ExtractAvbPublicKey(
627 misc_info['avb_avbtool'], signing_key)
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800628 print(" Rewriting AVB public key of system_other in /product")
629 common.ZipWrite(output_tf_zip, public_key, filename)
630
Bowgo Tsai78369eb2019-04-23 12:28:44 +0800631 # Should NOT sign boot-debug.img.
632 elif filename in (
633 "BOOT/RAMDISK/force_debuggable",
Bowgo Tsai2fe786a2020-02-21 17:48:18 +0800634 "BOOT/RAMDISK/first_stage_ramdisk/force_debuggable"):
Bowgo Tsai78369eb2019-04-23 12:28:44 +0800635 raise common.ExternalError("debuggable boot.img cannot be signed")
636
Tao Baoa80ed222016-06-16 14:41:24 -0700637 # A non-APK file; copy it verbatim.
Doug Zongkereef39442009-04-02 12:14:19 -0700638 else:
Tao Bao2ed665a2015-04-01 11:21:55 -0700639 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700640
Doug Zongker412c02f2014-02-13 10:58:24 -0800641 if OPTIONS.replace_ota_keys:
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700642 ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info)
Doug Zongker412c02f2014-02-13 10:58:24 -0800643
Tao Bao46a59992017-06-05 11:55:16 -0700644 # Replace the keyid string in misc_info dict.
Tao Bao8adcfd12016-06-17 17:01:22 -0700645 if OPTIONS.replace_verity_private_key:
Tao Bao46a59992017-06-05 11:55:16 -0700646 ReplaceVerityPrivateKey(misc_info, OPTIONS.replace_verity_private_key[1])
Tao Bao8adcfd12016-06-17 17:01:22 -0700647
648 if OPTIONS.replace_verity_public_key:
Tao Baoc9981932019-09-16 12:10:43 -0700649 # Replace the one in root dir in system.img.
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700650 ReplaceVerityPublicKey(
Tao Baoc9981932019-09-16 12:10:43 -0700651 output_tf_zip, 'ROOT/verity_key', OPTIONS.replace_verity_public_key[1])
652
653 if not system_root_image:
654 # Additionally replace the copy in ramdisk if not using system-as-root.
655 ReplaceVerityPublicKey(
656 output_tf_zip,
657 'BOOT/RAMDISK/verity_key',
658 OPTIONS.replace_verity_public_key[1])
Tao Bao8adcfd12016-06-17 17:01:22 -0700659
660 # Replace the keyid string in BOOT/cmdline.
661 if OPTIONS.replace_verity_keyid:
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700662 ReplaceVerityKeyId(input_tf_zip, output_tf_zip,
663 OPTIONS.replace_verity_keyid[1])
Doug Zongker412c02f2014-02-13 10:58:24 -0800664
Tao Bao639118f2017-06-19 15:48:02 -0700665 # Replace the AVB signing keys, if any.
666 ReplaceAvbSigningKeys(misc_info)
667
Tao Bao19b02fe2019-10-09 00:04:28 -0700668 # Rewrite the props in AVB signing args.
669 if misc_info.get('avb_enable') == 'true':
670 RewriteAvbProps(misc_info)
671
Tao Bao46a59992017-06-05 11:55:16 -0700672 # Write back misc_info with the latest values.
673 ReplaceMiscInfoTxt(input_tf_zip, output_tf_zip, misc_info)
674
Doug Zongker8e931bf2009-04-06 15:21:45 -0700675
Robert Craig817c5742013-04-19 10:59:22 -0400676def ReplaceCerts(data):
Tao Bao66472632017-12-04 17:16:36 -0800677 """Replaces all the occurences of X.509 certs with the new ones.
Robert Craig817c5742013-04-19 10:59:22 -0400678
Tao Bao66472632017-12-04 17:16:36 -0800679 The mapping info is read from OPTIONS.key_map. Non-existent certificate will
680 be skipped. After the replacement, it additionally checks for duplicate
681 entries, which would otherwise fail the policy loading code in
682 frameworks/base/services/core/java/com/android/server/pm/SELinuxMMAC.java.
683
684 Args:
685 data: Input string that contains a set of X.509 certs.
686
687 Returns:
688 A string after the replacement.
689
690 Raises:
691 AssertionError: On finding duplicate entries.
692 """
Tao Baoa3705452019-06-24 15:33:41 -0700693 for old, new in OPTIONS.key_map.items():
Tao Bao66472632017-12-04 17:16:36 -0800694 if OPTIONS.verbose:
695 print(" Replacing %s.x509.pem with %s.x509.pem" % (old, new))
696
697 try:
698 with open(old + ".x509.pem") as old_fp:
699 old_cert16 = base64.b16encode(
Tao Baoa3705452019-06-24 15:33:41 -0700700 common.ParseCertificate(old_fp.read())).decode().lower()
Tao Bao66472632017-12-04 17:16:36 -0800701 with open(new + ".x509.pem") as new_fp:
702 new_cert16 = base64.b16encode(
Tao Baoa3705452019-06-24 15:33:41 -0700703 common.ParseCertificate(new_fp.read())).decode().lower()
Tao Bao66472632017-12-04 17:16:36 -0800704 except IOError as e:
705 if OPTIONS.verbose or e.errno != errno.ENOENT:
706 print(" Error accessing %s: %s.\nSkip replacing %s.x509.pem with "
707 "%s.x509.pem." % (e.filename, e.strerror, old, new))
708 continue
709
710 # Only match entire certs.
711 pattern = "\\b" + old_cert16 + "\\b"
712 (data, num) = re.subn(pattern, new_cert16, data, flags=re.IGNORECASE)
713
714 if OPTIONS.verbose:
715 print(" Replaced %d occurence(s) of %s.x509.pem with %s.x509.pem" % (
716 num, old, new))
717
718 # Verify that there're no duplicate entries after the replacement. Note that
719 # it's only checking entries with global seinfo at the moment (i.e. ignoring
720 # the ones with inner packages). (Bug: 69479366)
721 root = ElementTree.fromstring(data)
722 signatures = [signer.attrib['signature'] for signer in root.findall('signer')]
723 assert len(signatures) == len(set(signatures)), \
724 "Found duplicate entries after cert replacement: {}".format(data)
Robert Craig817c5742013-04-19 10:59:22 -0400725
726 return data
727
728
Doug Zongkerc09abc82010-01-11 13:09:15 -0800729def EditTags(tags):
Tao Baoa7054ee2017-12-08 14:42:16 -0800730 """Applies the edits to the tag string as specified in OPTIONS.tag_changes.
731
732 Args:
733 tags: The input string that contains comma-separated tags.
734
735 Returns:
736 The updated tags (comma-separated and sorted).
737 """
Doug Zongkerc09abc82010-01-11 13:09:15 -0800738 tags = set(tags.split(","))
739 for ch in OPTIONS.tag_changes:
740 if ch[0] == "-":
741 tags.discard(ch[1:])
742 elif ch[0] == "+":
743 tags.add(ch[1:])
744 return ",".join(sorted(tags))
745
746
Tao Baoa7054ee2017-12-08 14:42:16 -0800747def RewriteProps(data):
748 """Rewrites the system properties in the given string.
749
750 Each property is expected in 'key=value' format. The properties that contain
751 build tags (i.e. test-keys, dev-keys) will be updated accordingly by calling
752 EditTags().
753
754 Args:
755 data: Input string, separated by newlines.
756
757 Returns:
758 The string with modified properties.
759 """
Doug Zongker17aa9442009-04-17 10:15:58 -0700760 output = []
761 for line in data.split("\n"):
762 line = line.strip()
763 original_line = line
Michael Rungedc2661a2014-06-03 14:43:11 -0700764 if line and line[0] != '#' and "=" in line:
Doug Zongker17aa9442009-04-17 10:15:58 -0700765 key, value = line.split("=", 1)
Magnus Strandh234f4b42019-05-01 23:09:30 +0200766 if (key.startswith("ro.") and
767 key.endswith((".build.fingerprint", ".build.thumbprint"))):
Doug Zongkerc09abc82010-01-11 13:09:15 -0800768 pieces = value.split("/")
769 pieces[-1] = EditTags(pieces[-1])
770 value = "/".join(pieces)
Tao Baocb7ff772015-09-11 15:27:56 -0700771 elif key == "ro.bootimage.build.fingerprint":
772 pieces = value.split("/")
773 pieces[-1] = EditTags(pieces[-1])
774 value = "/".join(pieces)
Doug Zongker17aa9442009-04-17 10:15:58 -0700775 elif key == "ro.build.description":
Doug Zongkerc09abc82010-01-11 13:09:15 -0800776 pieces = value.split(" ")
Doug Zongker17aa9442009-04-17 10:15:58 -0700777 assert len(pieces) == 5
Doug Zongkerc09abc82010-01-11 13:09:15 -0800778 pieces[-1] = EditTags(pieces[-1])
779 value = " ".join(pieces)
Magnus Strandh234f4b42019-05-01 23:09:30 +0200780 elif key.startswith("ro.") and key.endswith(".build.tags"):
Doug Zongkerc09abc82010-01-11 13:09:15 -0800781 value = EditTags(value)
Doug Zongkera8608a72013-07-23 11:51:04 -0700782 elif key == "ro.build.display.id":
783 # change, eg, "JWR66N dev-keys" to "JWR66N"
784 value = value.split()
Michael Rungedc2661a2014-06-03 14:43:11 -0700785 if len(value) > 1 and value[-1].endswith("-keys"):
Andrew Boie73d5abb2013-12-11 12:42:03 -0800786 value.pop()
787 value = " ".join(value)
Doug Zongkerc09abc82010-01-11 13:09:15 -0800788 line = key + "=" + value
Doug Zongker17aa9442009-04-17 10:15:58 -0700789 if line != original_line:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800790 print(" replace: ", original_line)
791 print(" with: ", line)
Doug Zongker17aa9442009-04-17 10:15:58 -0700792 output.append(line)
793 return "\n".join(output) + "\n"
794
795
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700796def WriteOtacerts(output_zip, filename, keys):
797 """Constructs a zipfile from given keys; and writes it to output_zip.
798
799 Args:
800 output_zip: The output target_files zip.
801 filename: The archive name in the output zip.
802 keys: A list of public keys to use during OTA package verification.
803 """
Tao Baobb733882019-07-24 23:31:19 -0700804 temp_file = io.BytesIO()
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700805 certs_zip = zipfile.ZipFile(temp_file, "w")
806 for k in keys:
807 common.ZipWrite(certs_zip, k)
808 common.ZipClose(certs_zip)
809 common.ZipWriteStr(output_zip, filename, temp_file.getvalue())
810
811
Doug Zongker831840e2011-09-22 10:28:04 -0700812def ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info):
Doug Zongker8e931bf2009-04-06 15:21:45 -0700813 try:
814 keylist = input_tf_zip.read("META/otakeys.txt").split()
815 except KeyError:
T.R. Fullharta28acc62013-03-18 10:31:26 -0700816 raise common.ExternalError("can't read META/otakeys.txt from input")
Doug Zongker8e931bf2009-04-06 15:21:45 -0700817
Tao Baof718f902017-11-09 10:10:10 -0800818 extra_recovery_keys = misc_info.get("extra_recovery_keys")
Doug Zongkere121d6a2011-02-01 14:13:52 -0800819 if extra_recovery_keys:
820 extra_recovery_keys = [OPTIONS.key_map.get(k, k) + ".x509.pem"
821 for k in extra_recovery_keys.split()]
822 if extra_recovery_keys:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800823 print("extra recovery-only key(s): " + ", ".join(extra_recovery_keys))
Doug Zongkere121d6a2011-02-01 14:13:52 -0800824 else:
825 extra_recovery_keys = []
826
Doug Zongker8e931bf2009-04-06 15:21:45 -0700827 mapped_keys = []
828 for k in keylist:
829 m = re.match(r"^(.*)\.x509\.pem$", k)
830 if not m:
Doug Zongker412c02f2014-02-13 10:58:24 -0800831 raise common.ExternalError(
832 "can't parse \"%s\" from META/otakeys.txt" % (k,))
Doug Zongker8e931bf2009-04-06 15:21:45 -0700833 k = m.group(1)
834 mapped_keys.append(OPTIONS.key_map.get(k, k) + ".x509.pem")
835
Doug Zongkere05628c2009-08-20 17:38:42 -0700836 if mapped_keys:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800837 print("using:\n ", "\n ".join(mapped_keys))
838 print("for OTA package verification")
Doug Zongkere05628c2009-08-20 17:38:42 -0700839 else:
Doug Zongker831840e2011-09-22 10:28:04 -0700840 devkey = misc_info.get("default_system_dev_certificate",
Dan Willemsen0ab1be62019-04-09 21:35:37 -0700841 "build/make/target/product/security/testkey")
Tao Baof718f902017-11-09 10:10:10 -0800842 mapped_devkey = OPTIONS.key_map.get(devkey, devkey)
843 if mapped_devkey != devkey:
844 misc_info["default_system_dev_certificate"] = mapped_devkey
845 mapped_keys.append(mapped_devkey + ".x509.pem")
Tao Baoa80ed222016-06-16 14:41:24 -0700846 print("META/otakeys.txt has no keys; using %s for OTA package"
847 " verification." % (mapped_keys[0],))
Doug Zongker8e931bf2009-04-06 15:21:45 -0700848
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700849 # recovery now uses the same x509.pem version of the keys.
Doug Zongkere121d6a2011-02-01 14:13:52 -0800850 # extra_recovery_keys are used only in recovery.
Tom Cherry2929cad2018-09-20 11:04:37 -0700851 if misc_info.get("recovery_as_boot") == "true":
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700852 recovery_keys_location = "BOOT/RAMDISK/system/etc/security/otacerts.zip"
Tao Baoa80ed222016-06-16 14:41:24 -0700853 else:
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700854 recovery_keys_location = "RECOVERY/RAMDISK/system/etc/security/otacerts.zip"
855
856 WriteOtacerts(output_tf_zip, recovery_keys_location,
857 mapped_keys + extra_recovery_keys)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700858
859 # SystemUpdateActivity uses the x509.pem version of the keys, but
860 # put into a zipfile system/etc/security/otacerts.zip.
Doug Zongkere121d6a2011-02-01 14:13:52 -0800861 # We DO NOT include the extra_recovery_keys (if any) here.
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700862 WriteOtacerts(output_tf_zip, "SYSTEM/etc/security/otacerts.zip", mapped_keys)
Doug Zongkereef39442009-04-02 12:14:19 -0700863
Tao Baoa80ed222016-06-16 14:41:24 -0700864
Tao Bao8adcfd12016-06-17 17:01:22 -0700865
Tao Bao0c28d2d2017-12-24 10:37:38 -0800866def ReplaceVerityPublicKey(output_zip, filename, key_path):
867 """Replaces the verity public key at the given path in the given zip.
868
869 Args:
870 output_zip: The output target_files zip.
871 filename: The archive name in the output zip.
872 key_path: The path to the public key.
873 """
874 print("Replacing verity public key with %s" % (key_path,))
875 common.ZipWrite(output_zip, key_path, arcname=filename)
Geremy Condraf19b3652014-07-29 17:54:54 -0700876
Tao Bao8adcfd12016-06-17 17:01:22 -0700877
Tao Bao46a59992017-06-05 11:55:16 -0700878def ReplaceVerityPrivateKey(misc_info, key_path):
Tao Bao0c28d2d2017-12-24 10:37:38 -0800879 """Replaces the verity private key in misc_info dict.
880
881 Args:
882 misc_info: The info dict.
883 key_path: The path to the private key in PKCS#8 format.
884 """
885 print("Replacing verity private key with %s" % (key_path,))
Andrew Boied083f0b2014-09-15 16:01:07 -0700886 misc_info["verity_key"] = key_path
Doug Zongkereef39442009-04-02 12:14:19 -0700887
Tao Bao8adcfd12016-06-17 17:01:22 -0700888
Tao Baoe838d142017-12-23 23:44:48 -0800889def ReplaceVerityKeyId(input_zip, output_zip, key_path):
890 """Replaces the veritykeyid parameter in BOOT/cmdline.
891
892 Args:
893 input_zip: The input target_files zip, which should be already open.
894 output_zip: The output target_files zip, which should be already open and
895 writable.
896 key_path: The path to the PEM encoded X.509 certificate.
897 """
Tao Baoa3705452019-06-24 15:33:41 -0700898 in_cmdline = input_zip.read("BOOT/cmdline").decode()
Tao Baoe838d142017-12-23 23:44:48 -0800899 # Copy in_cmdline to output_zip if veritykeyid is not present.
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700900 if "veritykeyid" not in in_cmdline:
Tao Baoe838d142017-12-23 23:44:48 -0800901 common.ZipWriteStr(output_zip, "BOOT/cmdline", in_cmdline)
902 return
903
Tao Bao0c28d2d2017-12-24 10:37:38 -0800904 out_buffer = []
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700905 for param in in_cmdline.split():
Tao Baoe838d142017-12-23 23:44:48 -0800906 if "veritykeyid" not in param:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800907 out_buffer.append(param)
Tao Baoe838d142017-12-23 23:44:48 -0800908 continue
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700909
Tao Baoe838d142017-12-23 23:44:48 -0800910 # Extract keyid using openssl command.
911 p = common.Run(["openssl", "x509", "-in", key_path, "-text"],
Tao Baode1d4792018-02-20 10:05:46 -0800912 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
Tao Baoe838d142017-12-23 23:44:48 -0800913 keyid, stderr = p.communicate()
914 assert p.returncode == 0, "Failed to dump certificate: {}".format(stderr)
915 keyid = re.search(
916 r'keyid:([0-9a-fA-F:]*)', keyid).group(1).replace(':', '').lower()
917 print("Replacing verity keyid with {}".format(keyid))
918 out_buffer.append("veritykeyid=id:%s" % (keyid,))
919
920 out_cmdline = ' '.join(out_buffer).strip() + '\n'
921 common.ZipWriteStr(output_zip, "BOOT/cmdline", out_cmdline)
Tao Bao46a59992017-06-05 11:55:16 -0700922
923
924def ReplaceMiscInfoTxt(input_zip, output_zip, misc_info):
925 """Replaces META/misc_info.txt.
926
927 Only writes back the ones in the original META/misc_info.txt. Because the
928 current in-memory dict contains additional items computed at runtime.
929 """
930 misc_info_old = common.LoadDictionaryFromLines(
Tao Baoa3705452019-06-24 15:33:41 -0700931 input_zip.read('META/misc_info.txt').decode().split('\n'))
Tao Bao46a59992017-06-05 11:55:16 -0700932 items = []
933 for key in sorted(misc_info):
934 if key in misc_info_old:
935 items.append('%s=%s' % (key, misc_info[key]))
936 common.ZipWriteStr(output_zip, "META/misc_info.txt", '\n'.join(items))
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700937
Tao Bao8adcfd12016-06-17 17:01:22 -0700938
Tao Bao639118f2017-06-19 15:48:02 -0700939def ReplaceAvbSigningKeys(misc_info):
940 """Replaces the AVB signing keys."""
941
Tao Bao639118f2017-06-19 15:48:02 -0700942 def ReplaceAvbPartitionSigningKey(partition):
943 key = OPTIONS.avb_keys.get(partition)
944 if not key:
945 return
946
947 algorithm = OPTIONS.avb_algorithms.get(partition)
948 assert algorithm, 'Missing AVB signing algorithm for %s' % (partition,)
949
Tao Bao0c28d2d2017-12-24 10:37:38 -0800950 print('Replacing AVB signing key for %s with "%s" (%s)' % (
951 partition, key, algorithm))
Tao Bao639118f2017-06-19 15:48:02 -0700952 misc_info['avb_' + partition + '_algorithm'] = algorithm
953 misc_info['avb_' + partition + '_key_path'] = key
954
955 extra_args = OPTIONS.avb_extra_args.get(partition)
956 if extra_args:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800957 print('Setting extra AVB signing args for %s to "%s"' % (
958 partition, extra_args))
Tao Bao639118f2017-06-19 15:48:02 -0700959 args_key = AVB_FOOTER_ARGS_BY_PARTITION[partition]
960 misc_info[args_key] = (misc_info.get(args_key, '') + ' ' + extra_args)
961
962 for partition in AVB_FOOTER_ARGS_BY_PARTITION:
963 ReplaceAvbPartitionSigningKey(partition)
964
965
Tao Bao19b02fe2019-10-09 00:04:28 -0700966def RewriteAvbProps(misc_info):
967 """Rewrites the props in AVB signing args."""
968 for partition, args_key in AVB_FOOTER_ARGS_BY_PARTITION.items():
969 args = misc_info.get(args_key)
970 if not args:
971 continue
972
973 tokens = []
974 changed = False
975 for token in args.split(' '):
976 fingerprint_key = 'com.android.build.{}.fingerprint'.format(partition)
977 if not token.startswith(fingerprint_key):
978 tokens.append(token)
979 continue
980 prefix, tag = token.rsplit('/', 1)
981 tokens.append('{}/{}'.format(prefix, EditTags(tag)))
982 changed = True
983
984 if changed:
985 result = ' '.join(tokens)
986 print('Rewriting AVB prop for {}:\n'.format(partition))
987 print(' replace: {}'.format(args))
988 print(' with: {}'.format(result))
989 misc_info[args_key] = result
990
991
Doug Zongker831840e2011-09-22 10:28:04 -0700992def BuildKeyMap(misc_info, key_mapping_options):
993 for s, d in key_mapping_options:
994 if s is None: # -d option
995 devkey = misc_info.get("default_system_dev_certificate",
Dan Willemsen0ab1be62019-04-09 21:35:37 -0700996 "build/make/target/product/security/testkey")
Doug Zongker831840e2011-09-22 10:28:04 -0700997 devkeydir = os.path.dirname(devkey)
998
999 OPTIONS.key_map.update({
1000 devkeydir + "/testkey": d + "/releasekey",
1001 devkeydir + "/devkey": d + "/releasekey",
1002 devkeydir + "/media": d + "/media",
1003 devkeydir + "/shared": d + "/shared",
1004 devkeydir + "/platform": d + "/platform",
Oleh Cherpak982e6082019-12-10 12:58:54 +02001005 devkeydir + "/networkstack": d + "/networkstack",
Doug Zongker831840e2011-09-22 10:28:04 -07001006 })
1007 else:
1008 OPTIONS.key_map[s] = d
1009
1010
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001011def GetApiLevelAndCodename(input_tf_zip):
Tao Baoa3705452019-06-24 15:33:41 -07001012 data = input_tf_zip.read("SYSTEM/build.prop").decode()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001013 api_level = None
1014 codename = None
1015 for line in data.split("\n"):
1016 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001017 if line and line[0] != '#' and "=" in line:
1018 key, value = line.split("=", 1)
1019 key = key.strip()
1020 if key == "ro.build.version.sdk":
1021 api_level = int(value.strip())
1022 elif key == "ro.build.version.codename":
1023 codename = value.strip()
1024
1025 if api_level is None:
1026 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
1027 if codename is None:
1028 raise ValueError("No ro.build.version.codename in SYSTEM/build.prop")
1029
1030 return (api_level, codename)
1031
1032
1033def GetCodenameToApiLevelMap(input_tf_zip):
Tao Baoa3705452019-06-24 15:33:41 -07001034 data = input_tf_zip.read("SYSTEM/build.prop").decode()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001035 api_level = None
1036 codenames = None
1037 for line in data.split("\n"):
1038 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001039 if line and line[0] != '#' and "=" in line:
1040 key, value = line.split("=", 1)
1041 key = key.strip()
1042 if key == "ro.build.version.sdk":
1043 api_level = int(value.strip())
1044 elif key == "ro.build.version.all_codenames":
1045 codenames = value.strip().split(",")
1046
1047 if api_level is None:
1048 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
1049 if codenames is None:
1050 raise ValueError("No ro.build.version.all_codenames in SYSTEM/build.prop")
1051
Tao Baoa3705452019-06-24 15:33:41 -07001052 result = {}
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001053 for codename in codenames:
1054 codename = codename.strip()
Tao Baobadceb22019-03-15 09:33:43 -07001055 if codename:
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001056 result[codename] = api_level
1057 return result
1058
1059
Tao Baoaa7e9932019-03-15 09:37:01 -07001060def ReadApexKeysInfo(tf_zip):
1061 """Parses the APEX keys info from a given target-files zip.
1062
1063 Given a target-files ZipFile, parses the META/apexkeys.txt entry and returns a
1064 dict that contains the mapping from APEX names (e.g. com.android.tzdata) to a
1065 tuple of (payload_key, container_key).
1066
1067 Args:
1068 tf_zip: The input target_files ZipFile (already open).
1069
1070 Returns:
1071 (payload_key, container_key): payload_key contains the path to the payload
1072 signing key; container_key contains the path to the container signing
1073 key.
1074 """
1075 keys = {}
Tao Baoa3705452019-06-24 15:33:41 -07001076 for line in tf_zip.read('META/apexkeys.txt').decode().split('\n'):
Tao Baoaa7e9932019-03-15 09:37:01 -07001077 line = line.strip()
1078 if not line:
1079 continue
1080 matches = re.match(
1081 r'^name="(?P<NAME>.*)"\s+'
1082 r'public_key="(?P<PAYLOAD_PUBLIC_KEY>.*)"\s+'
1083 r'private_key="(?P<PAYLOAD_PRIVATE_KEY>.*)"\s+'
1084 r'container_certificate="(?P<CONTAINER_CERT>.*)"\s+'
1085 r'container_private_key="(?P<CONTAINER_PRIVATE_KEY>.*)"$',
1086 line)
1087 if not matches:
1088 continue
1089
1090 name = matches.group('NAME')
Tao Baoaa7e9932019-03-15 09:37:01 -07001091 payload_private_key = matches.group("PAYLOAD_PRIVATE_KEY")
1092
1093 def CompareKeys(pubkey, pubkey_suffix, privkey, privkey_suffix):
1094 pubkey_suffix_len = len(pubkey_suffix)
1095 privkey_suffix_len = len(privkey_suffix)
1096 return (pubkey.endswith(pubkey_suffix) and
1097 privkey.endswith(privkey_suffix) and
1098 pubkey[:-pubkey_suffix_len] == privkey[:-privkey_suffix_len])
1099
Tao Bao6d9e3da2019-03-26 12:59:25 -07001100 # Sanity check on the container key names, as we'll carry them without the
1101 # extensions. This doesn't apply to payload keys though, which we will use
1102 # full names only.
Tao Baoaa7e9932019-03-15 09:37:01 -07001103 container_cert = matches.group("CONTAINER_CERT")
1104 container_private_key = matches.group("CONTAINER_PRIVATE_KEY")
Tao Baof454c3a2019-04-24 23:53:42 -07001105 if container_cert == 'PRESIGNED' and container_private_key == 'PRESIGNED':
1106 container_key = 'PRESIGNED'
1107 elif CompareKeys(
Tao Baoaa7e9932019-03-15 09:37:01 -07001108 container_cert, OPTIONS.public_key_suffix,
1109 container_private_key, OPTIONS.private_key_suffix):
Tao Baof454c3a2019-04-24 23:53:42 -07001110 container_key = container_cert[:-len(OPTIONS.public_key_suffix)]
1111 else:
Tao Baoaa7e9932019-03-15 09:37:01 -07001112 raise ValueError("Failed to parse container keys: \n{}".format(line))
1113
Tao Baof454c3a2019-04-24 23:53:42 -07001114 keys[name] = (payload_private_key, container_key)
Tao Baoaa7e9932019-03-15 09:37:01 -07001115
1116 return keys
1117
1118
Doug Zongkereef39442009-04-02 12:14:19 -07001119def main(argv):
1120
Doug Zongker831840e2011-09-22 10:28:04 -07001121 key_mapping_options = []
1122
Doug Zongkereef39442009-04-02 12:14:19 -07001123 def option_handler(o, a):
Doug Zongker05d3dea2009-06-22 11:32:31 -07001124 if o in ("-e", "--extra_apks"):
Doug Zongkereef39442009-04-02 12:14:19 -07001125 names, key = a.split("=")
1126 names = names.split(",")
1127 for n in names:
1128 OPTIONS.extra_apks[n] = key
Tao Baoaa7e9932019-03-15 09:37:01 -07001129 elif o == "--extra_apex_payload_key":
1130 apex_name, key = a.split("=")
1131 OPTIONS.extra_apex_payload_keys[apex_name] = key
Tao Bao93c2a012018-06-19 12:19:35 -07001132 elif o == "--skip_apks_with_path_prefix":
1133 # Sanity check the prefix, which must be in all upper case.
1134 prefix = a.split('/')[0]
1135 if not prefix or prefix != prefix.upper():
1136 raise ValueError("Invalid path prefix '%s'" % (a,))
1137 OPTIONS.skip_apks_with_path_prefix.add(a)
Doug Zongkereef39442009-04-02 12:14:19 -07001138 elif o in ("-d", "--default_key_mappings"):
Doug Zongker831840e2011-09-22 10:28:04 -07001139 key_mapping_options.append((None, a))
Doug Zongkereef39442009-04-02 12:14:19 -07001140 elif o in ("-k", "--key_mapping"):
Doug Zongker831840e2011-09-22 10:28:04 -07001141 key_mapping_options.append(a.split("=", 1))
Doug Zongker8e931bf2009-04-06 15:21:45 -07001142 elif o in ("-o", "--replace_ota_keys"):
1143 OPTIONS.replace_ota_keys = True
Doug Zongkerae877012009-04-21 10:04:51 -07001144 elif o in ("-t", "--tag_changes"):
1145 new = []
1146 for i in a.split(","):
1147 i = i.strip()
1148 if not i or i[0] not in "-+":
1149 raise ValueError("Bad tag change '%s'" % (i,))
1150 new.append(i[0] + i[1:].strip())
1151 OPTIONS.tag_changes = tuple(new)
Geremy Condraf19b3652014-07-29 17:54:54 -07001152 elif o == "--replace_verity_public_key":
1153 OPTIONS.replace_verity_public_key = (True, a)
1154 elif o == "--replace_verity_private_key":
1155 OPTIONS.replace_verity_private_key = (True, a)
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001156 elif o == "--replace_verity_keyid":
1157 OPTIONS.replace_verity_keyid = (True, a)
Bowgo Tsai2fe786a2020-02-21 17:48:18 +08001158 elif o == "--remove_avb_public_keys":
1159 OPTIONS.remove_avb_public_keys = a.split(",")
Tao Bao639118f2017-06-19 15:48:02 -07001160 elif o == "--avb_vbmeta_key":
1161 OPTIONS.avb_keys['vbmeta'] = a
1162 elif o == "--avb_vbmeta_algorithm":
1163 OPTIONS.avb_algorithms['vbmeta'] = a
1164 elif o == "--avb_vbmeta_extra_args":
1165 OPTIONS.avb_extra_args['vbmeta'] = a
1166 elif o == "--avb_boot_key":
1167 OPTIONS.avb_keys['boot'] = a
1168 elif o == "--avb_boot_algorithm":
1169 OPTIONS.avb_algorithms['boot'] = a
1170 elif o == "--avb_boot_extra_args":
1171 OPTIONS.avb_extra_args['boot'] = a
1172 elif o == "--avb_dtbo_key":
1173 OPTIONS.avb_keys['dtbo'] = a
1174 elif o == "--avb_dtbo_algorithm":
1175 OPTIONS.avb_algorithms['dtbo'] = a
1176 elif o == "--avb_dtbo_extra_args":
1177 OPTIONS.avb_extra_args['dtbo'] = a
1178 elif o == "--avb_system_key":
1179 OPTIONS.avb_keys['system'] = a
1180 elif o == "--avb_system_algorithm":
1181 OPTIONS.avb_algorithms['system'] = a
1182 elif o == "--avb_system_extra_args":
1183 OPTIONS.avb_extra_args['system'] = a
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001184 elif o == "--avb_system_other_key":
1185 OPTIONS.avb_keys['system_other'] = a
1186 elif o == "--avb_system_other_algorithm":
1187 OPTIONS.avb_algorithms['system_other'] = a
1188 elif o == "--avb_system_other_extra_args":
1189 OPTIONS.avb_extra_args['system_other'] = a
Tao Bao639118f2017-06-19 15:48:02 -07001190 elif o == "--avb_vendor_key":
1191 OPTIONS.avb_keys['vendor'] = a
1192 elif o == "--avb_vendor_algorithm":
1193 OPTIONS.avb_algorithms['vendor'] = a
1194 elif o == "--avb_vendor_extra_args":
1195 OPTIONS.avb_extra_args['vendor'] = a
Tao Baod6085d62019-05-06 12:55:42 -07001196 elif o == "--avb_vbmeta_system_key":
1197 OPTIONS.avb_keys['vbmeta_system'] = a
1198 elif o == "--avb_vbmeta_system_algorithm":
1199 OPTIONS.avb_algorithms['vbmeta_system'] = a
1200 elif o == "--avb_vbmeta_system_extra_args":
1201 OPTIONS.avb_extra_args['vbmeta_system'] = a
1202 elif o == "--avb_vbmeta_vendor_key":
1203 OPTIONS.avb_keys['vbmeta_vendor'] = a
1204 elif o == "--avb_vbmeta_vendor_algorithm":
1205 OPTIONS.avb_algorithms['vbmeta_vendor'] = a
1206 elif o == "--avb_vbmeta_vendor_extra_args":
1207 OPTIONS.avb_extra_args['vbmeta_vendor'] = a
Tao Baoaa7e9932019-03-15 09:37:01 -07001208 elif o == "--avb_apex_extra_args":
1209 OPTIONS.avb_extra_args['apex'] = a
Doug Zongkereef39442009-04-02 12:14:19 -07001210 else:
1211 return False
1212 return True
1213
Tao Bao639118f2017-06-19 15:48:02 -07001214 args = common.ParseOptions(
1215 argv, __doc__,
1216 extra_opts="e:d:k:ot:",
1217 extra_long_opts=[
Tao Bao0c28d2d2017-12-24 10:37:38 -08001218 "extra_apks=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001219 "extra_apex_payload_key=",
Tao Bao93c2a012018-06-19 12:19:35 -07001220 "skip_apks_with_path_prefix=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001221 "default_key_mappings=",
1222 "key_mapping=",
1223 "replace_ota_keys",
1224 "tag_changes=",
1225 "replace_verity_public_key=",
1226 "replace_verity_private_key=",
1227 "replace_verity_keyid=",
Bowgo Tsai2fe786a2020-02-21 17:48:18 +08001228 "remove_avb_public_keys=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001229 "avb_apex_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001230 "avb_vbmeta_algorithm=",
1231 "avb_vbmeta_key=",
1232 "avb_vbmeta_extra_args=",
1233 "avb_boot_algorithm=",
1234 "avb_boot_key=",
1235 "avb_boot_extra_args=",
1236 "avb_dtbo_algorithm=",
1237 "avb_dtbo_key=",
1238 "avb_dtbo_extra_args=",
1239 "avb_system_algorithm=",
1240 "avb_system_key=",
1241 "avb_system_extra_args=",
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001242 "avb_system_other_algorithm=",
1243 "avb_system_other_key=",
1244 "avb_system_other_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001245 "avb_vendor_algorithm=",
1246 "avb_vendor_key=",
1247 "avb_vendor_extra_args=",
Tao Baod6085d62019-05-06 12:55:42 -07001248 "avb_vbmeta_system_algorithm=",
1249 "avb_vbmeta_system_key=",
1250 "avb_vbmeta_system_extra_args=",
1251 "avb_vbmeta_vendor_algorithm=",
1252 "avb_vbmeta_vendor_key=",
1253 "avb_vbmeta_vendor_extra_args=",
Tao Bao639118f2017-06-19 15:48:02 -07001254 ],
1255 extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001256
1257 if len(args) != 2:
1258 common.Usage(__doc__)
1259 sys.exit(1)
1260
Tao Baobadceb22019-03-15 09:33:43 -07001261 common.InitLogging()
1262
Doug Zongkereef39442009-04-02 12:14:19 -07001263 input_zip = zipfile.ZipFile(args[0], "r")
Tao Bao2b8f4892017-06-13 12:54:58 -07001264 output_zip = zipfile.ZipFile(args[1], "w",
1265 compression=zipfile.ZIP_DEFLATED,
1266 allowZip64=True)
Doug Zongkereef39442009-04-02 12:14:19 -07001267
Doug Zongker831840e2011-09-22 10:28:04 -07001268 misc_info = common.LoadInfoDict(input_zip)
1269
1270 BuildKeyMap(misc_info, key_mapping_options)
1271
Tao Baoaa7e9932019-03-15 09:37:01 -07001272 apk_keys_info, compressed_extension = common.ReadApkCerts(input_zip)
1273 apk_keys = GetApkCerts(apk_keys_info)
Doug Zongkereb338ef2009-05-20 16:50:49 -07001274
Tao Baoaa7e9932019-03-15 09:37:01 -07001275 apex_keys_info = ReadApexKeysInfo(input_zip)
1276 apex_keys = GetApexKeys(apex_keys_info, apk_keys)
1277
Tianjie Xu88a759d2020-01-23 10:47:54 -08001278 # TODO(xunchang) check for the apks inside the apex files, and abort early if
1279 # the keys are not available.
Tao Baoaa7e9932019-03-15 09:37:01 -07001280 CheckApkAndApexKeysAvailable(
1281 input_zip,
1282 set(apk_keys.keys()) | set(apex_keys.keys()),
Tao Baoe1343992019-03-19 12:24:03 -07001283 compressed_extension,
1284 apex_keys)
Tao Baoaa7e9932019-03-15 09:37:01 -07001285
1286 key_passwords = common.GetKeyPasswords(
1287 set(apk_keys.values()) | set(itertools.chain(*apex_keys.values())))
Tao Bao9aa4b9b2016-09-29 17:53:56 -07001288 platform_api_level, _ = GetApiLevelAndCodename(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001289 codename_to_api_level_map = GetCodenameToApiLevelMap(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001290
Doug Zongker412c02f2014-02-13 10:58:24 -08001291 ProcessTargetFiles(input_zip, output_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -07001292 apk_keys, apex_keys, key_passwords,
1293 platform_api_level, codename_to_api_level_map,
Narayan Kamatha07bf042017-08-14 14:49:21 +01001294 compressed_extension)
Doug Zongker8e931bf2009-04-06 15:21:45 -07001295
Tao Bao2ed665a2015-04-01 11:21:55 -07001296 common.ZipClose(input_zip)
1297 common.ZipClose(output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001298
Tianjie Xub48589a2016-08-03 19:21:52 -07001299 # Skip building userdata.img and cache.img when signing the target files.
Tianjie Xu616fbeb2017-05-23 14:51:02 -07001300 new_args = ["--is_signing"]
1301 # add_img_to_target_files builds the system image from scratch, so the
1302 # recovery patch is guaranteed to be regenerated there.
1303 if OPTIONS.rebuild_recovery:
1304 new_args.append("--rebuild_recovery")
1305 new_args.append(args[1])
Tianjie Xub48589a2016-08-03 19:21:52 -07001306 add_img_to_target_files.main(new_args)
Doug Zongker3c84f562014-07-31 11:06:30 -07001307
Tao Bao0c28d2d2017-12-24 10:37:38 -08001308 print("done.")
Doug Zongkereef39442009-04-02 12:14:19 -07001309
1310
1311if __name__ == '__main__':
1312 try:
1313 main(sys.argv[1:])
Tao Bao0c28d2d2017-12-24 10:37:38 -08001314 except common.ExternalError as e:
1315 print("\n ERROR: %s\n" % (e,))
Doug Zongkereef39442009-04-02 12:14:19 -07001316 sys.exit(1)
Tao Bao639118f2017-06-19 15:48:02 -07001317 finally:
1318 common.Cleanup()