blob: f0110eaaab384844ff89f5995fd7440bb4a1a5a6 [file] [log] [blame]
Doug Zongkereef39442009-04-02 12:14:19 -07001#!/usr/bin/env python
2#
3# Copyright (C) 2008 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17"""
18Signs all the APK files in a target-files zipfile, producing a new
19target-files zip.
20
21Usage: sign_target_files_apks [flags] input_target_files output_target_files
22
Doug Zongkereef39442009-04-02 12:14:19 -070023 -e (--extra_apks) <name,name,...=key>
Tao Baoaa7e9932019-03-15 09:37:01 -070024 Add extra APK/APEX name/key pairs as though they appeared in apkcerts.txt
25 or apexkeys.txt (so mappings specified by -k and -d are applied). Keys
26 specified in -e override any value for that app contained in the
27 apkcerts.txt file, or the container key for an APEX. Option may be
28 repeated to give multiple extra packages.
29
30 --extra_apex_payload_key <name=key>
31 Add a mapping for APEX package name to payload signing key, which will
32 override the default payload signing key in apexkeys.txt. Note that the
33 container key should be overridden via the `--extra_apks` flag above.
34 Option may be repeated for multiple APEXes.
Doug Zongkereef39442009-04-02 12:14:19 -070035
Tao Bao93c2a012018-06-19 12:19:35 -070036 --skip_apks_with_path_prefix <prefix>
37 Skip signing an APK if it has the matching prefix in its path. The prefix
38 should be matching the entry name, which has partition names in upper
39 case, e.g. "VENDOR/app/", or "SYSTEM_OTHER/preloads/". Option may be
40 repeated to give multiple prefixes.
41
Doug Zongkereef39442009-04-02 12:14:19 -070042 -k (--key_mapping) <src_key=dest_key>
43 Add a mapping from the key name as specified in apkcerts.txt (the
44 src_key) to the real key you wish to sign the package with
45 (dest_key). Option may be repeated to give multiple key
46 mappings.
47
48 -d (--default_key_mappings) <dir>
49 Set up the following key mappings:
50
Doug Zongker831840e2011-09-22 10:28:04 -070051 $devkey/devkey ==> $dir/releasekey
52 $devkey/testkey ==> $dir/releasekey
53 $devkey/media ==> $dir/media
54 $devkey/shared ==> $dir/shared
55 $devkey/platform ==> $dir/platform
56
57 where $devkey is the directory part of the value of
58 default_system_dev_certificate from the input target-files's
Dan Willemsen0ab1be62019-04-09 21:35:37 -070059 META/misc_info.txt. (Defaulting to "build/make/target/product/security"
Doug Zongker831840e2011-09-22 10:28:04 -070060 if the value is not present in misc_info.
Doug Zongkereef39442009-04-02 12:14:19 -070061
62 -d and -k options are added to the set of mappings in the order
63 in which they appear on the command line.
Doug Zongker8e931bf2009-04-06 15:21:45 -070064
65 -o (--replace_ota_keys)
Tao Baoa80ed222016-06-16 14:41:24 -070066 Replace the certificate (public key) used by OTA package verification
67 with the ones specified in the input target_files zip (in the
68 META/otakeys.txt file). Key remapping (-k and -d) is performed on the
69 keys. For A/B devices, the payload verification key will be replaced
70 as well. If there're multiple OTA keys, only the first one will be used
71 for payload verification.
Doug Zongker17aa9442009-04-17 10:15:58 -070072
Doug Zongkerae877012009-04-21 10:04:51 -070073 -t (--tag_changes) <+tag>,<-tag>,...
74 Comma-separated list of changes to make to the set of tags (in
75 the last component of the build fingerprint). Prefix each with
76 '+' or '-' to indicate whether that tag should be added or
77 removed. Changes are processed in the order they appear.
Doug Zongker831840e2011-09-22 10:28:04 -070078 Default value is "-test-keys,-dev-keys,+release-keys".
Doug Zongkerae877012009-04-21 10:04:51 -070079
Tao Bao8adcfd12016-06-17 17:01:22 -070080 --replace_verity_private_key <key>
81 Replace the private key used for verity signing. It expects a filename
82 WITHOUT the extension (e.g. verity_key).
83
84 --replace_verity_public_key <key>
85 Replace the certificate (public key) used for verity verification. The
86 key file replaces the one at BOOT/RAMDISK/verity_key (or ROOT/verity_key
87 for devices using system_root_image). It expects the key filename WITH
88 the extension (e.g. verity_key.pub).
89
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -070090 --replace_verity_keyid <path_to_X509_PEM_cert_file>
91 Replace the veritykeyid in BOOT/cmdline of input_target_file_zip
Tao Bao8adcfd12016-06-17 17:01:22 -070092 with keyid of the cert pointed by <path_to_X509_PEM_cert_file>.
Tao Bao639118f2017-06-19 15:48:02 -070093
Bowgo Tsai2fe786a2020-02-21 17:48:18 +080094 --remove_avb_public_keys <key1>,<key2>,...
95 Remove AVB public keys from the first-stage ramdisk. The key file to
96 remove is located at either of the following dirs:
97 - BOOT/RAMDISK/avb/ or
98 - BOOT/RAMDISK/first_stage_ramdisk/avb/
99 The second dir will be used for lookup if BOARD_USES_RECOVERY_AS_BOOT is
100 set to true.
101
Tao Baod6085d62019-05-06 12:55:42 -0700102 --avb_{boot,system,system_other,vendor,dtbo,vbmeta,vbmeta_system,
103 vbmeta_vendor}_algorithm <algorithm>
104 --avb_{boot,system,system_other,vendor,dtbo,vbmeta,vbmeta_system,
105 vbmeta_vendor}_key <key>
Tao Bao639118f2017-06-19 15:48:02 -0700106 Use the specified algorithm (e.g. SHA256_RSA4096) and the key to AVB-sign
107 the specified image. Otherwise it uses the existing values in info dict.
108
Tao Baod6085d62019-05-06 12:55:42 -0700109 --avb_{apex,boot,system,system_other,vendor,dtbo,vbmeta,vbmeta_system,
110 vbmeta_vendor}_extra_args <args>
Tao Bao639118f2017-06-19 15:48:02 -0700111 Specify any additional args that are needed to AVB-sign the image
112 (e.g. "--signing_helper /path/to/helper"). The args will be appended to
113 the existing ones in info dict.
Tianjie Xu88a759d2020-01-23 10:47:54 -0800114
Hongguang Chenf23364d2020-04-27 18:36:36 -0700115 --avb_extra_custom_image_key <partition=key>
116 --avb_extra_custom_image_algorithm <partition=algorithm>
117 Use the specified algorithm (e.g. SHA256_RSA4096) and the key to AVB-sign
118 the specified custom images mounted on the partition. Otherwise it uses
119 the existing values in info dict.
120
121 --avb_extra_custom_image_extra_args <partition=extra_args>
122 Specify any additional args that are needed to AVB-sign the custom images
123 mounted on the partition (e.g. "--signing_helper /path/to/helper"). The
124 args will be appended to the existing ones in info dict.
125
Bowgo Tsai27c39b02021-03-12 21:40:32 +0800126 --gki_signing_algorithm <algorithm>
127 --gki_signing_key <key>
128 Use the specified algorithm (e.g. SHA256_RSA4096) and the key to generate
129 'boot signature' in a v4 boot.img. Otherwise it uses the existing values
130 in info dict.
131
132 --gki_signing_extra_args <args>
133 Specify any additional args that are needed to generate 'boot signature'
134 (e.g. --prop foo:bar). The args will be appended to the existing ones
135 in info dict.
136
Tianjie Xu88a759d2020-01-23 10:47:54 -0800137 --android_jar_path <path>
138 Path to the android.jar to repack the apex file.
Doug Zongkereef39442009-04-02 12:14:19 -0700139"""
140
Tao Bao0c28d2d2017-12-24 10:37:38 -0800141from __future__ import print_function
Doug Zongkereef39442009-04-02 12:14:19 -0700142
Robert Craig817c5742013-04-19 10:59:22 -0400143import base64
Doug Zongker8e931bf2009-04-06 15:21:45 -0700144import copy
Robert Craig817c5742013-04-19 10:59:22 -0400145import errno
Narayan Kamatha07bf042017-08-14 14:49:21 +0100146import gzip
Tao Baobb733882019-07-24 23:31:19 -0700147import io
Tao Baoaa7e9932019-03-15 09:37:01 -0700148import itertools
Tao Baobadceb22019-03-15 09:33:43 -0700149import logging
Doug Zongkereef39442009-04-02 12:14:19 -0700150import os
151import re
Narayan Kamatha07bf042017-08-14 14:49:21 +0100152import shutil
Tao Bao9fdd00f2017-07-12 11:57:05 -0700153import stat
Doug Zongkereef39442009-04-02 12:14:19 -0700154import subprocess
Tao Bao0c28d2d2017-12-24 10:37:38 -0800155import sys
Doug Zongkereef39442009-04-02 12:14:19 -0700156import tempfile
157import zipfile
Tao Bao66472632017-12-04 17:16:36 -0800158from xml.etree import ElementTree
Doug Zongkereef39442009-04-02 12:14:19 -0700159
Doug Zongker3c84f562014-07-31 11:06:30 -0700160import add_img_to_target_files
Tao Baoaa7e9932019-03-15 09:37:01 -0700161import apex_utils
Doug Zongkereef39442009-04-02 12:14:19 -0700162import common
163
Tao Bao0c28d2d2017-12-24 10:37:38 -0800164
165if sys.hexversion < 0x02070000:
166 print("Python 2.7 or newer is required.", file=sys.stderr)
167 sys.exit(1)
168
169
Tao Baobadceb22019-03-15 09:33:43 -0700170logger = logging.getLogger(__name__)
171
Doug Zongkereef39442009-04-02 12:14:19 -0700172OPTIONS = common.OPTIONS
173
174OPTIONS.extra_apks = {}
Tao Baoaa7e9932019-03-15 09:37:01 -0700175OPTIONS.extra_apex_payload_keys = {}
Tao Bao93c2a012018-06-19 12:19:35 -0700176OPTIONS.skip_apks_with_path_prefix = set()
Doug Zongkereef39442009-04-02 12:14:19 -0700177OPTIONS.key_map = {}
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700178OPTIONS.rebuild_recovery = False
Doug Zongker8e931bf2009-04-06 15:21:45 -0700179OPTIONS.replace_ota_keys = False
Geremy Condraf19b3652014-07-29 17:54:54 -0700180OPTIONS.replace_verity_public_key = False
181OPTIONS.replace_verity_private_key = False
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700182OPTIONS.replace_verity_keyid = False
Bowgo Tsai2fe786a2020-02-21 17:48:18 +0800183OPTIONS.remove_avb_public_keys = None
Doug Zongker831840e2011-09-22 10:28:04 -0700184OPTIONS.tag_changes = ("-test-keys", "-dev-keys", "+release-keys")
Tao Bao639118f2017-06-19 15:48:02 -0700185OPTIONS.avb_keys = {}
186OPTIONS.avb_algorithms = {}
187OPTIONS.avb_extra_args = {}
Bowgo Tsai27c39b02021-03-12 21:40:32 +0800188OPTIONS.gki_signing_key = None
189OPTIONS.gki_signing_algorithm = None
190OPTIONS.gki_signing_extra_args = None
Tianjie Xu88a759d2020-01-23 10:47:54 -0800191OPTIONS.android_jar_path = None
Doug Zongkereef39442009-04-02 12:14:19 -0700192
Tao Bao0c28d2d2017-12-24 10:37:38 -0800193
Tao Bao19b02fe2019-10-09 00:04:28 -0700194AVB_FOOTER_ARGS_BY_PARTITION = {
Tianjiebf0b8a82021-03-03 17:31:04 -0800195 'boot': 'avb_boot_add_hash_footer_args',
196 'dtbo': 'avb_dtbo_add_hash_footer_args',
197 'product': 'avb_product_add_hashtree_footer_args',
198 'recovery': 'avb_recovery_add_hash_footer_args',
199 'system': 'avb_system_add_hashtree_footer_args',
200 'system_ext': 'avb_system_ext_add_hashtree_footer_args',
201 'system_other': 'avb_system_other_add_hashtree_footer_args',
202 'odm': 'avb_odm_add_hashtree_footer_args',
203 'odm_dlkm': 'avb_odm_dlkm_add_hashtree_footer_args',
204 'pvmfw': 'avb_pvmfw_add_hash_footer_args',
205 'vendor': 'avb_vendor_add_hashtree_footer_args',
206 'vendor_boot': 'avb_vendor_boot_add_hash_footer_args',
207 'vendor_dlkm': "avb_vendor_dlkm_add_hashtree_footer_args",
208 'vbmeta': 'avb_vbmeta_args',
209 'vbmeta_system': 'avb_vbmeta_system_args',
210 'vbmeta_vendor': 'avb_vbmeta_vendor_args',
Tao Bao19b02fe2019-10-09 00:04:28 -0700211}
212
213
Tianjiebf0b8a82021-03-03 17:31:04 -0800214# Check that AVB_FOOTER_ARGS_BY_PARTITION is in sync with AVB_PARTITIONS.
215for partition in common.AVB_PARTITIONS:
216 if partition not in AVB_FOOTER_ARGS_BY_PARTITION:
217 raise RuntimeError("Missing {} in AVB_FOOTER_ARGS".format(partition))
218
219
Narayan Kamatha07bf042017-08-14 14:49:21 +0100220def GetApkCerts(certmap):
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800221 # apply the key remapping to the contents of the file
Tao Baoa3705452019-06-24 15:33:41 -0700222 for apk, cert in certmap.items():
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800223 certmap[apk] = OPTIONS.key_map.get(cert, cert)
224
225 # apply all the -e options, overriding anything in the file
Tao Baoa3705452019-06-24 15:33:41 -0700226 for apk, cert in OPTIONS.extra_apks.items():
Doug Zongkerdecf9952009-12-15 17:27:49 -0800227 if not cert:
228 cert = "PRESIGNED"
Doug Zongkerad88c7c2009-04-14 12:34:27 -0700229 certmap[apk] = OPTIONS.key_map.get(cert, cert)
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800230
Doug Zongkereef39442009-04-02 12:14:19 -0700231 return certmap
232
233
Tao Baoaa7e9932019-03-15 09:37:01 -0700234def GetApexKeys(keys_info, key_map):
235 """Gets APEX payload and container signing keys by applying the mapping rules.
236
Tao Baoe1343992019-03-19 12:24:03 -0700237 Presigned payload / container keys will be set accordingly.
Tao Baoaa7e9932019-03-15 09:37:01 -0700238
239 Args:
240 keys_info: A dict that maps from APEX filenames to a tuple of (payload_key,
241 container_key).
242 key_map: A dict that overrides the keys, specified via command-line input.
243
244 Returns:
245 A dict that contains the updated APEX key mapping, which should be used for
246 the current signing.
Tao Baof98fa102019-04-24 14:51:25 -0700247
248 Raises:
249 AssertionError: On invalid container / payload key overrides.
Tao Baoaa7e9932019-03-15 09:37:01 -0700250 """
251 # Apply all the --extra_apex_payload_key options to override the payload
252 # signing keys in the given keys_info.
253 for apex, key in OPTIONS.extra_apex_payload_keys.items():
Tao Baoe1343992019-03-19 12:24:03 -0700254 if not key:
255 key = 'PRESIGNED'
Tao Bao34223092019-07-11 11:52:52 -0700256 if apex not in keys_info:
257 logger.warning('Failed to find %s in target_files; Ignored', apex)
258 continue
Tao Baoaa7e9932019-03-15 09:37:01 -0700259 keys_info[apex] = (key, keys_info[apex][1])
260
261 # Apply the key remapping to container keys.
262 for apex, (payload_key, container_key) in keys_info.items():
263 keys_info[apex] = (payload_key, key_map.get(container_key, container_key))
264
265 # Apply all the --extra_apks options to override the container keys.
266 for apex, key in OPTIONS.extra_apks.items():
267 # Skip non-APEX containers.
268 if apex not in keys_info:
269 continue
Tao Baoe1343992019-03-19 12:24:03 -0700270 if not key:
271 key = 'PRESIGNED'
Tao Baofa9de0a2019-03-18 10:24:17 -0700272 keys_info[apex] = (keys_info[apex][0], key_map.get(key, key))
Tao Baoaa7e9932019-03-15 09:37:01 -0700273
Tao Baof98fa102019-04-24 14:51:25 -0700274 # A PRESIGNED container entails a PRESIGNED payload. Apply this to all the
275 # APEX key pairs. However, a PRESIGNED container with non-PRESIGNED payload
276 # (overridden via commandline) indicates a config error, which should not be
277 # allowed.
278 for apex, (payload_key, container_key) in keys_info.items():
279 if container_key != 'PRESIGNED':
280 continue
281 if apex in OPTIONS.extra_apex_payload_keys:
282 payload_override = OPTIONS.extra_apex_payload_keys[apex]
283 assert payload_override == '', \
284 ("Invalid APEX key overrides: {} has PRESIGNED container but "
285 "non-PRESIGNED payload key {}").format(apex, payload_override)
286 if payload_key != 'PRESIGNED':
287 print(
288 "Setting {} payload as PRESIGNED due to PRESIGNED container".format(
289 apex))
290 keys_info[apex] = ('PRESIGNED', 'PRESIGNED')
291
Tao Baoaa7e9932019-03-15 09:37:01 -0700292 return keys_info
293
294
Tao Bao93c2a012018-06-19 12:19:35 -0700295def GetApkFileInfo(filename, compressed_extension, skipped_prefixes):
Tao Bao11f955c2018-06-19 12:19:35 -0700296 """Returns the APK info based on the given filename.
297
298 Checks if the given filename (with path) looks like an APK file, by taking the
Tao Bao93c2a012018-06-19 12:19:35 -0700299 compressed extension into consideration. If it appears to be an APK file,
300 further checks if the APK file should be skipped when signing, based on the
301 given path prefixes.
Tao Bao11f955c2018-06-19 12:19:35 -0700302
303 Args:
304 filename: Path to the file.
305 compressed_extension: The extension string of compressed APKs (e.g. ".gz"),
306 or None if there's no compressed APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700307 skipped_prefixes: A set/list/tuple of the path prefixes to be skipped.
Tao Bao11f955c2018-06-19 12:19:35 -0700308
309 Returns:
Tao Bao93c2a012018-06-19 12:19:35 -0700310 (is_apk, is_compressed, should_be_skipped): is_apk indicates whether the
311 given filename is an APK file. is_compressed indicates whether the APK file
312 is compressed (only meaningful when is_apk is True). should_be_skipped
313 indicates whether the filename matches any of the given prefixes to be
314 skipped.
Tao Bao11f955c2018-06-19 12:19:35 -0700315
316 Raises:
Tao Bao93c2a012018-06-19 12:19:35 -0700317 AssertionError: On invalid compressed_extension or skipped_prefixes inputs.
Tao Bao11f955c2018-06-19 12:19:35 -0700318 """
319 assert compressed_extension is None or compressed_extension.startswith('.'), \
320 "Invalid compressed_extension arg: '{}'".format(compressed_extension)
321
Tao Bao93c2a012018-06-19 12:19:35 -0700322 # skipped_prefixes should be one of set/list/tuple types. Other types such as
323 # str shouldn't be accepted.
Tao Baobadceb22019-03-15 09:33:43 -0700324 assert isinstance(skipped_prefixes, (set, list, tuple)), \
325 "Invalid skipped_prefixes input type: {}".format(type(skipped_prefixes))
Tao Bao93c2a012018-06-19 12:19:35 -0700326
Tao Bao11f955c2018-06-19 12:19:35 -0700327 compressed_apk_extension = (
328 ".apk" + compressed_extension if compressed_extension else None)
329 is_apk = (filename.endswith(".apk") or
330 (compressed_apk_extension and
331 filename.endswith(compressed_apk_extension)))
332 if not is_apk:
Tao Bao93c2a012018-06-19 12:19:35 -0700333 return (False, False, False)
Tao Bao11f955c2018-06-19 12:19:35 -0700334
335 is_compressed = (compressed_apk_extension and
336 filename.endswith(compressed_apk_extension))
Tao Bao93c2a012018-06-19 12:19:35 -0700337 should_be_skipped = filename.startswith(tuple(skipped_prefixes))
338 return (True, is_compressed, should_be_skipped)
Tao Bao11f955c2018-06-19 12:19:35 -0700339
340
Tao Baoaa7e9932019-03-15 09:37:01 -0700341def CheckApkAndApexKeysAvailable(input_tf_zip, known_keys,
Tao Baoe1343992019-03-19 12:24:03 -0700342 compressed_extension, apex_keys):
Tao Baoaa7e9932019-03-15 09:37:01 -0700343 """Checks that all the APKs and APEXes have keys specified.
Tao Bao11f955c2018-06-19 12:19:35 -0700344
345 Args:
346 input_tf_zip: An open target_files zip file.
Tao Baoaa7e9932019-03-15 09:37:01 -0700347 known_keys: A set of APKs and APEXes that have known signing keys.
Tao Bao11f955c2018-06-19 12:19:35 -0700348 compressed_extension: The extension string of compressed APKs, such as
Tao Baoaa7e9932019-03-15 09:37:01 -0700349 '.gz', or None if there's no compressed APKs.
Tao Baoe1343992019-03-19 12:24:03 -0700350 apex_keys: A dict that contains the key mapping from APEX name to
351 (payload_key, container_key).
Tao Bao11f955c2018-06-19 12:19:35 -0700352
353 Raises:
Tao Baoaa7e9932019-03-15 09:37:01 -0700354 AssertionError: On finding unknown APKs and APEXes.
Tao Bao11f955c2018-06-19 12:19:35 -0700355 """
Tao Baoaa7e9932019-03-15 09:37:01 -0700356 unknown_files = []
Doug Zongkereb338ef2009-05-20 16:50:49 -0700357 for info in input_tf_zip.infolist():
Tianjie5bd03952021-02-18 23:02:36 -0800358 # Handle APEXes on all partitions
359 if info.filename.endswith('.apex'):
Tao Baoaa7e9932019-03-15 09:37:01 -0700360 name = os.path.basename(info.filename)
361 if name not in known_keys:
362 unknown_files.append(name)
363 continue
364
365 # And APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700366 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
367 info.filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
368 if not is_apk or should_be_skipped:
Tao Bao11f955c2018-06-19 12:19:35 -0700369 continue
Tao Baoaa7e9932019-03-15 09:37:01 -0700370
Tao Bao11f955c2018-06-19 12:19:35 -0700371 name = os.path.basename(info.filename)
372 if is_compressed:
373 name = name[:-len(compressed_extension)]
Tao Baoaa7e9932019-03-15 09:37:01 -0700374 if name not in known_keys:
375 unknown_files.append(name)
Tao Bao11f955c2018-06-19 12:19:35 -0700376
Tao Baoaa7e9932019-03-15 09:37:01 -0700377 assert not unknown_files, \
Tao Bao11f955c2018-06-19 12:19:35 -0700378 ("No key specified for:\n {}\n"
379 "Use '-e <apkname>=' to specify a key (which may be an empty string to "
Tao Baoaa7e9932019-03-15 09:37:01 -0700380 "not sign this apk).".format("\n ".join(unknown_files)))
Doug Zongkereb338ef2009-05-20 16:50:49 -0700381
Tao Baoe1343992019-03-19 12:24:03 -0700382 # For all the APEXes, double check that we won't have an APEX that has only
Tao Baof98fa102019-04-24 14:51:25 -0700383 # one of the payload / container keys set. Note that non-PRESIGNED container
384 # with PRESIGNED payload could be allowed but currently unsupported. It would
385 # require changing SignApex implementation.
Tao Baoe1343992019-03-19 12:24:03 -0700386 if not apex_keys:
387 return
388
389 invalid_apexes = []
390 for info in input_tf_zip.infolist():
Tianjie5bd03952021-02-18 23:02:36 -0800391 if not info.filename.endswith('.apex'):
Tao Baoe1343992019-03-19 12:24:03 -0700392 continue
393
394 name = os.path.basename(info.filename)
395 (payload_key, container_key) = apex_keys[name]
396 if ((payload_key in common.SPECIAL_CERT_STRINGS and
397 container_key not in common.SPECIAL_CERT_STRINGS) or
398 (payload_key not in common.SPECIAL_CERT_STRINGS and
399 container_key in common.SPECIAL_CERT_STRINGS)):
400 invalid_apexes.append(
401 "{}: payload_key {}, container_key {}".format(
402 name, payload_key, container_key))
403
404 assert not invalid_apexes, \
405 "Invalid APEX keys specified:\n {}\n".format(
406 "\n ".join(invalid_apexes))
407
Doug Zongkereb338ef2009-05-20 16:50:49 -0700408
Narayan Kamatha07bf042017-08-14 14:49:21 +0100409def SignApk(data, keyname, pw, platform_api_level, codename_to_api_level_map,
Oleg Aravin8046cb02020-06-02 16:02:38 -0700410 is_compressed, apk_name):
411 unsigned = tempfile.NamedTemporaryFile(suffix='_' + apk_name)
Doug Zongkereef39442009-04-02 12:14:19 -0700412 unsigned.write(data)
413 unsigned.flush()
414
Narayan Kamatha07bf042017-08-14 14:49:21 +0100415 if is_compressed:
416 uncompressed = tempfile.NamedTemporaryFile()
Tao Bao0c28d2d2017-12-24 10:37:38 -0800417 with gzip.open(unsigned.name, "rb") as in_file, \
418 open(uncompressed.name, "wb") as out_file:
Narayan Kamatha07bf042017-08-14 14:49:21 +0100419 shutil.copyfileobj(in_file, out_file)
420
421 # Finally, close the "unsigned" file (which is gzip compressed), and then
422 # replace it with the uncompressed version.
423 #
424 # TODO(narayan): All this nastiness can be avoided if python 3.2 is in use,
425 # we could just gzip / gunzip in-memory buffers instead.
426 unsigned.close()
427 unsigned = uncompressed
428
Oleg Aravin8046cb02020-06-02 16:02:38 -0700429 signed = tempfile.NamedTemporaryFile(suffix='_' + apk_name)
Doug Zongkereef39442009-04-02 12:14:19 -0700430
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800431 # For pre-N builds, don't upgrade to SHA-256 JAR signatures based on the APK's
432 # minSdkVersion to avoid increasing incremental OTA update sizes. If an APK
433 # didn't change, we don't want its signature to change due to the switch
434 # from SHA-1 to SHA-256.
435 # By default, APK signer chooses SHA-256 signatures if the APK's minSdkVersion
436 # is 18 or higher. For pre-N builds we disable this mechanism by pretending
437 # that the APK's minSdkVersion is 1.
438 # For N+ builds, we let APK signer rely on the APK's minSdkVersion to
439 # determine whether to use SHA-256.
440 min_api_level = None
441 if platform_api_level > 23:
442 # Let APK signer choose whether to use SHA-1 or SHA-256, based on the APK's
443 # minSdkVersion attribute
444 min_api_level = None
445 else:
446 # Force APK signer to use SHA-1
447 min_api_level = 1
448
449 common.SignFile(unsigned.name, signed.name, keyname, pw,
Tao Bao0c28d2d2017-12-24 10:37:38 -0800450 min_api_level=min_api_level,
451 codename_to_api_level_map=codename_to_api_level_map)
Doug Zongkereef39442009-04-02 12:14:19 -0700452
Tao Bao0c28d2d2017-12-24 10:37:38 -0800453 data = None
Narayan Kamatha07bf042017-08-14 14:49:21 +0100454 if is_compressed:
455 # Recompress the file after it has been signed.
456 compressed = tempfile.NamedTemporaryFile()
Tao Bao0c28d2d2017-12-24 10:37:38 -0800457 with open(signed.name, "rb") as in_file, \
458 gzip.open(compressed.name, "wb") as out_file:
Narayan Kamatha07bf042017-08-14 14:49:21 +0100459 shutil.copyfileobj(in_file, out_file)
460
461 data = compressed.read()
462 compressed.close()
463 else:
464 data = signed.read()
465
Doug Zongkereef39442009-04-02 12:14:19 -0700466 unsigned.close()
467 signed.close()
468
469 return data
470
Tianjie5bd03952021-02-18 23:02:36 -0800471
Kelvin Zhang119f2792021-02-10 12:45:24 -0500472def IsBuildPropFile(filename):
473 return filename in (
474 "SYSTEM/etc/prop.default",
475 "BOOT/RAMDISK/prop.default",
476 "RECOVERY/RAMDISK/prop.default",
477
478 "VENDOR_BOOT/RAMDISK/default.prop",
479 "VENDOR_BOOT/RAMDISK/prop.default",
480
481 # ROOT/default.prop is a legacy path, but may still exist for upgrading
482 # devices that don't support `property_overrides_split_enabled`.
483 "ROOT/default.prop",
484
485 # RECOVERY/RAMDISK/default.prop is a legacy path, but will always exist
486 # as a symlink in the current code. So it's a no-op here. Keeping the
487 # path here for clarity.
488 "RECOVERY/RAMDISK/default.prop") or filename.endswith("build.prop")
Doug Zongkereef39442009-04-02 12:14:19 -0700489
Tianjie5bd03952021-02-18 23:02:36 -0800490
Doug Zongker412c02f2014-02-13 10:58:24 -0800491def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -0700492 apk_keys, apex_keys, key_passwords,
493 platform_api_level, codename_to_api_level_map,
Narayan Kamatha07bf042017-08-14 14:49:21 +0100494 compressed_extension):
Tao Bao93c2a012018-06-19 12:19:35 -0700495 # maxsize measures the maximum filename length, including the ones to be
496 # skipped.
Tao Bao0c28d2d2017-12-24 10:37:38 -0800497 maxsize = max(
498 [len(os.path.basename(i.filename)) for i in input_tf_zip.infolist()
Tao Bao93c2a012018-06-19 12:19:35 -0700499 if GetApkFileInfo(i.filename, compressed_extension, [])[0]])
Tao Baoa80ed222016-06-16 14:41:24 -0700500 system_root_image = misc_info.get("system_root_image") == "true"
Doug Zongker412c02f2014-02-13 10:58:24 -0800501
Doug Zongkereef39442009-04-02 12:14:19 -0700502 for info in input_tf_zip.infolist():
Tao Bao11f955c2018-06-19 12:19:35 -0700503 filename = info.filename
504 if filename.startswith("IMAGES/"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700505 continue
Doug Zongker3c84f562014-07-31 11:06:30 -0700506
Tao Bao04808502019-07-25 23:11:41 -0700507 # Skip OTA-specific images (e.g. split super images), which will be
508 # re-generated during signing.
Tao Bao33bf2682019-01-11 12:37:35 -0800509 if filename.startswith("OTA/") and filename.endswith(".img"):
510 continue
511
Tao Bao11f955c2018-06-19 12:19:35 -0700512 data = input_tf_zip.read(filename)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700513 out_info = copy.copy(info)
Tao Bao93c2a012018-06-19 12:19:35 -0700514 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
515 filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
516
517 if is_apk and should_be_skipped:
518 # Copy skipped APKs verbatim.
519 print(
520 "NOT signing: %s\n"
521 " (skipped due to matching prefix)" % (filename,))
522 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker412c02f2014-02-13 10:58:24 -0800523
Tao Baof2cffbd2015-07-22 12:33:18 -0700524 # Sign APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700525 elif is_apk:
Tao Bao11f955c2018-06-19 12:19:35 -0700526 name = os.path.basename(filename)
Narayan Kamatha07bf042017-08-14 14:49:21 +0100527 if is_compressed:
528 name = name[:-len(compressed_extension)]
529
Tao Baoaa7e9932019-03-15 09:37:01 -0700530 key = apk_keys[name]
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800531 if key not in common.SPECIAL_CERT_STRINGS:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800532 print(" signing: %-*s (%s)" % (maxsize, name, key))
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800533 signed_data = SignApk(data, key, key_passwords[key], platform_api_level,
Oleg Aravin8046cb02020-06-02 16:02:38 -0700534 codename_to_api_level_map, is_compressed, name)
Tao Bao2ed665a2015-04-01 11:21:55 -0700535 common.ZipWriteStr(output_tf_zip, out_info, signed_data)
Doug Zongkereef39442009-04-02 12:14:19 -0700536 else:
537 # an APK we're not supposed to sign.
Tao Bao93c2a012018-06-19 12:19:35 -0700538 print(
539 "NOT signing: %s\n"
540 " (skipped due to special cert string)" % (name,))
Tao Bao2ed665a2015-04-01 11:21:55 -0700541 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoa80ed222016-06-16 14:41:24 -0700542
Tianjie5bd03952021-02-18 23:02:36 -0800543 # Sign bundled APEX files on all partitions
544 elif filename.endswith(".apex"):
Tao Baoaa7e9932019-03-15 09:37:01 -0700545 name = os.path.basename(filename)
546 payload_key, container_key = apex_keys[name]
547
Tao Baoe1343992019-03-19 12:24:03 -0700548 # We've asserted not having a case with only one of them PRESIGNED.
549 if (payload_key not in common.SPECIAL_CERT_STRINGS and
550 container_key not in common.SPECIAL_CERT_STRINGS):
551 print(" signing: %-*s container (%s)" % (
552 maxsize, name, container_key))
553 print(" : %-*s payload (%s)" % (
554 maxsize, name, payload_key))
Tao Baoaa7e9932019-03-15 09:37:01 -0700555
Tao Baoe7354ba2019-05-09 16:54:15 -0700556 signed_apex = apex_utils.SignApex(
Tao Bao1ac886e2019-06-26 11:58:22 -0700557 misc_info['avb_avbtool'],
Tao Baoe1343992019-03-19 12:24:03 -0700558 data,
559 payload_key,
560 container_key,
Oleh Cherpake555ab12020-10-05 17:04:59 +0300561 key_passwords,
Tianjie Xu88a759d2020-01-23 10:47:54 -0800562 apk_keys,
Tao Baoe1343992019-03-19 12:24:03 -0700563 codename_to_api_level_map,
Tao Bao448004a2019-09-19 07:55:02 -0700564 no_hashtree=True,
565 signing_args=OPTIONS.avb_extra_args.get('apex'))
Tao Baoe1343992019-03-19 12:24:03 -0700566 common.ZipWrite(output_tf_zip, signed_apex, filename)
Tao Baoaa7e9932019-03-15 09:37:01 -0700567
Tao Baoe1343992019-03-19 12:24:03 -0700568 else:
569 print(
570 "NOT signing: %s\n"
571 " (skipped due to special cert string)" % (name,))
572 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoaa7e9932019-03-15 09:37:01 -0700573
Tao Baoa80ed222016-06-16 14:41:24 -0700574 # System properties.
Kelvin Zhang119f2792021-02-10 12:45:24 -0500575 elif IsBuildPropFile(filename):
Tao Bao11f955c2018-06-19 12:19:35 -0700576 print("Rewriting %s:" % (filename,))
Hung-ying Tyan7eb6a922017-05-01 21:56:26 +0800577 if stat.S_ISLNK(info.external_attr >> 16):
578 new_data = data
579 else:
Tao Baoa3705452019-06-24 15:33:41 -0700580 new_data = RewriteProps(data.decode())
Tao Bao2ed665a2015-04-01 11:21:55 -0700581 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700582
Tao Bao66472632017-12-04 17:16:36 -0800583 # Replace the certs in *mac_permissions.xml (there could be multiple, such
584 # as {system,vendor}/etc/selinux/{plat,nonplat}_mac_permissions.xml).
Tao Bao11f955c2018-06-19 12:19:35 -0700585 elif filename.endswith("mac_permissions.xml"):
586 print("Rewriting %s with new keys." % (filename,))
Tao Baoa3705452019-06-24 15:33:41 -0700587 new_data = ReplaceCerts(data.decode())
Tao Bao2ed665a2015-04-01 11:21:55 -0700588 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700589
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700590 # Ask add_img_to_target_files to rebuild the recovery patch if needed.
Tao Bao11f955c2018-06-19 12:19:35 -0700591 elif filename in ("SYSTEM/recovery-from-boot.p",
Robin Leeda427de2020-01-03 19:16:32 +0100592 "VENDOR/recovery-from-boot.p",
593
Tao Bao11f955c2018-06-19 12:19:35 -0700594 "SYSTEM/etc/recovery.img",
Robin Leeda427de2020-01-03 19:16:32 +0100595 "VENDOR/etc/recovery.img",
596
597 "SYSTEM/bin/install-recovery.sh",
598 "VENDOR/bin/install-recovery.sh"):
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700599 OPTIONS.rebuild_recovery = True
Tao Baoa80ed222016-06-16 14:41:24 -0700600
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700601 # Don't copy OTA certs if we're replacing them.
Tianjie Xu2df23d72019-10-15 18:06:25 -0700602 # Replacement of update-payload-key.pub.pem was removed in b/116660991.
Kelvin Zhang9f781ff2021-02-11 19:10:44 -0500603 elif OPTIONS.replace_ota_keys and filename.endswith("/otacerts.zip"):
Doug Zongker412c02f2014-02-13 10:58:24 -0800604 pass
Tao Baoa80ed222016-06-16 14:41:24 -0700605
Tao Bao46a59992017-06-05 11:55:16 -0700606 # Skip META/misc_info.txt since we will write back the new values later.
Tao Bao11f955c2018-06-19 12:19:35 -0700607 elif filename == "META/misc_info.txt":
Geremy Condraf19b3652014-07-29 17:54:54 -0700608 pass
Tao Bao8adcfd12016-06-17 17:01:22 -0700609
610 # Skip verity public key if we will replace it.
Michael Runge947894f2014-10-14 20:58:38 -0700611 elif (OPTIONS.replace_verity_public_key and
Tao Bao11f955c2018-06-19 12:19:35 -0700612 filename in ("BOOT/RAMDISK/verity_key",
613 "ROOT/verity_key")):
Geremy Condraf19b3652014-07-29 17:54:54 -0700614 pass
Bowgo Tsai2fe786a2020-02-21 17:48:18 +0800615 elif (OPTIONS.remove_avb_public_keys and
616 (filename.startswith("BOOT/RAMDISK/avb/") or
617 filename.startswith("BOOT/RAMDISK/first_stage_ramdisk/avb/"))):
Kelvin Zhang0876c412020-06-23 15:06:58 -0400618 matched_removal = False
619 for key_to_remove in OPTIONS.remove_avb_public_keys:
620 if filename.endswith(key_to_remove):
621 matched_removal = True
622 print("Removing AVB public key from ramdisk: %s" % filename)
623 break
624 if not matched_removal:
625 # Copy it verbatim if we don't want to remove it.
626 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoa80ed222016-06-16 14:41:24 -0700627
Tao Bao8adcfd12016-06-17 17:01:22 -0700628 # Skip verity keyid (for system_root_image use) if we will replace it.
Tao Bao11f955c2018-06-19 12:19:35 -0700629 elif OPTIONS.replace_verity_keyid and filename == "BOOT/cmdline":
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700630 pass
631
Tianjiebbde59f2021-05-03 21:18:56 -0700632 # Skip the vbmeta digest as we will recalculate it.
633 elif filename == "META/vbmeta_digest.txt":
634 pass
635
Tianjie Xu4f099002016-08-11 18:04:27 -0700636 # Skip the care_map as we will regenerate the system/vendor images.
Kelvin Zhang0876c412020-06-23 15:06:58 -0400637 elif filename in ["META/care_map.pb", "META/care_map.txt"]:
Tianjie Xu4f099002016-08-11 18:04:27 -0700638 pass
639
Kelvin Zhang5f0fcee2021-01-19 15:30:46 -0500640 # Skip apex_info.pb because we sign/modify apexes
641 elif filename == "META/apex_info.pb":
642 pass
643
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800644 # Updates system_other.avbpubkey in /product/etc/.
645 elif filename in (
646 "PRODUCT/etc/security/avb/system_other.avbpubkey",
647 "SYSTEM/product/etc/security/avb/system_other.avbpubkey"):
648 # Only update system_other's public key, if the corresponding signing
649 # key is specified via --avb_system_other_key.
650 signing_key = OPTIONS.avb_keys.get("system_other")
651 if signing_key:
Tao Bao1ac886e2019-06-26 11:58:22 -0700652 public_key = common.ExtractAvbPublicKey(
653 misc_info['avb_avbtool'], signing_key)
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800654 print(" Rewriting AVB public key of system_other in /product")
655 common.ZipWrite(output_tf_zip, public_key, filename)
656
Bowgo Tsai78369eb2019-04-23 12:28:44 +0800657 # Should NOT sign boot-debug.img.
658 elif filename in (
659 "BOOT/RAMDISK/force_debuggable",
Bowgo Tsai2fe786a2020-02-21 17:48:18 +0800660 "BOOT/RAMDISK/first_stage_ramdisk/force_debuggable"):
Bowgo Tsai78369eb2019-04-23 12:28:44 +0800661 raise common.ExternalError("debuggable boot.img cannot be signed")
662
Tao Baoa80ed222016-06-16 14:41:24 -0700663 # A non-APK file; copy it verbatim.
Doug Zongkereef39442009-04-02 12:14:19 -0700664 else:
Tao Bao2ed665a2015-04-01 11:21:55 -0700665 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700666
Doug Zongker412c02f2014-02-13 10:58:24 -0800667 if OPTIONS.replace_ota_keys:
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700668 ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info)
Doug Zongker412c02f2014-02-13 10:58:24 -0800669
Tao Bao46a59992017-06-05 11:55:16 -0700670 # Replace the keyid string in misc_info dict.
Tao Bao8adcfd12016-06-17 17:01:22 -0700671 if OPTIONS.replace_verity_private_key:
Tao Bao46a59992017-06-05 11:55:16 -0700672 ReplaceVerityPrivateKey(misc_info, OPTIONS.replace_verity_private_key[1])
Tao Bao8adcfd12016-06-17 17:01:22 -0700673
674 if OPTIONS.replace_verity_public_key:
Tao Baoc9981932019-09-16 12:10:43 -0700675 # Replace the one in root dir in system.img.
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700676 ReplaceVerityPublicKey(
Tao Baoc9981932019-09-16 12:10:43 -0700677 output_tf_zip, 'ROOT/verity_key', OPTIONS.replace_verity_public_key[1])
678
679 if not system_root_image:
680 # Additionally replace the copy in ramdisk if not using system-as-root.
681 ReplaceVerityPublicKey(
682 output_tf_zip,
683 'BOOT/RAMDISK/verity_key',
684 OPTIONS.replace_verity_public_key[1])
Tao Bao8adcfd12016-06-17 17:01:22 -0700685
686 # Replace the keyid string in BOOT/cmdline.
687 if OPTIONS.replace_verity_keyid:
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700688 ReplaceVerityKeyId(input_tf_zip, output_tf_zip,
689 OPTIONS.replace_verity_keyid[1])
Doug Zongker412c02f2014-02-13 10:58:24 -0800690
Tao Bao639118f2017-06-19 15:48:02 -0700691 # Replace the AVB signing keys, if any.
692 ReplaceAvbSigningKeys(misc_info)
693
Tao Bao19b02fe2019-10-09 00:04:28 -0700694 # Rewrite the props in AVB signing args.
695 if misc_info.get('avb_enable') == 'true':
696 RewriteAvbProps(misc_info)
697
Bowgo Tsai27c39b02021-03-12 21:40:32 +0800698 # Replace the GKI signing key for boot.img, if any.
699 ReplaceGkiSigningKey(misc_info)
700
Tao Bao46a59992017-06-05 11:55:16 -0700701 # Write back misc_info with the latest values.
702 ReplaceMiscInfoTxt(input_tf_zip, output_tf_zip, misc_info)
703
Doug Zongker8e931bf2009-04-06 15:21:45 -0700704
Robert Craig817c5742013-04-19 10:59:22 -0400705def ReplaceCerts(data):
Tao Bao66472632017-12-04 17:16:36 -0800706 """Replaces all the occurences of X.509 certs with the new ones.
Robert Craig817c5742013-04-19 10:59:22 -0400707
Tao Bao66472632017-12-04 17:16:36 -0800708 The mapping info is read from OPTIONS.key_map. Non-existent certificate will
709 be skipped. After the replacement, it additionally checks for duplicate
710 entries, which would otherwise fail the policy loading code in
711 frameworks/base/services/core/java/com/android/server/pm/SELinuxMMAC.java.
712
713 Args:
714 data: Input string that contains a set of X.509 certs.
715
716 Returns:
717 A string after the replacement.
718
719 Raises:
720 AssertionError: On finding duplicate entries.
721 """
Tao Baoa3705452019-06-24 15:33:41 -0700722 for old, new in OPTIONS.key_map.items():
Tao Bao66472632017-12-04 17:16:36 -0800723 if OPTIONS.verbose:
724 print(" Replacing %s.x509.pem with %s.x509.pem" % (old, new))
725
726 try:
727 with open(old + ".x509.pem") as old_fp:
728 old_cert16 = base64.b16encode(
Tao Baoa3705452019-06-24 15:33:41 -0700729 common.ParseCertificate(old_fp.read())).decode().lower()
Tao Bao66472632017-12-04 17:16:36 -0800730 with open(new + ".x509.pem") as new_fp:
731 new_cert16 = base64.b16encode(
Tao Baoa3705452019-06-24 15:33:41 -0700732 common.ParseCertificate(new_fp.read())).decode().lower()
Tao Bao66472632017-12-04 17:16:36 -0800733 except IOError as e:
734 if OPTIONS.verbose or e.errno != errno.ENOENT:
735 print(" Error accessing %s: %s.\nSkip replacing %s.x509.pem with "
736 "%s.x509.pem." % (e.filename, e.strerror, old, new))
737 continue
738
739 # Only match entire certs.
740 pattern = "\\b" + old_cert16 + "\\b"
741 (data, num) = re.subn(pattern, new_cert16, data, flags=re.IGNORECASE)
742
743 if OPTIONS.verbose:
744 print(" Replaced %d occurence(s) of %s.x509.pem with %s.x509.pem" % (
745 num, old, new))
746
747 # Verify that there're no duplicate entries after the replacement. Note that
748 # it's only checking entries with global seinfo at the moment (i.e. ignoring
749 # the ones with inner packages). (Bug: 69479366)
750 root = ElementTree.fromstring(data)
751 signatures = [signer.attrib['signature'] for signer in root.findall('signer')]
752 assert len(signatures) == len(set(signatures)), \
753 "Found duplicate entries after cert replacement: {}".format(data)
Robert Craig817c5742013-04-19 10:59:22 -0400754
755 return data
756
757
Doug Zongkerc09abc82010-01-11 13:09:15 -0800758def EditTags(tags):
Tao Baoa7054ee2017-12-08 14:42:16 -0800759 """Applies the edits to the tag string as specified in OPTIONS.tag_changes.
760
761 Args:
762 tags: The input string that contains comma-separated tags.
763
764 Returns:
765 The updated tags (comma-separated and sorted).
766 """
Doug Zongkerc09abc82010-01-11 13:09:15 -0800767 tags = set(tags.split(","))
768 for ch in OPTIONS.tag_changes:
769 if ch[0] == "-":
770 tags.discard(ch[1:])
771 elif ch[0] == "+":
772 tags.add(ch[1:])
773 return ",".join(sorted(tags))
774
775
Tao Baoa7054ee2017-12-08 14:42:16 -0800776def RewriteProps(data):
777 """Rewrites the system properties in the given string.
778
779 Each property is expected in 'key=value' format. The properties that contain
780 build tags (i.e. test-keys, dev-keys) will be updated accordingly by calling
781 EditTags().
782
783 Args:
784 data: Input string, separated by newlines.
785
786 Returns:
787 The string with modified properties.
788 """
Doug Zongker17aa9442009-04-17 10:15:58 -0700789 output = []
790 for line in data.split("\n"):
791 line = line.strip()
792 original_line = line
Michael Rungedc2661a2014-06-03 14:43:11 -0700793 if line and line[0] != '#' and "=" in line:
Doug Zongker17aa9442009-04-17 10:15:58 -0700794 key, value = line.split("=", 1)
Magnus Strandh234f4b42019-05-01 23:09:30 +0200795 if (key.startswith("ro.") and
796 key.endswith((".build.fingerprint", ".build.thumbprint"))):
Doug Zongkerc09abc82010-01-11 13:09:15 -0800797 pieces = value.split("/")
798 pieces[-1] = EditTags(pieces[-1])
799 value = "/".join(pieces)
Tao Baocb7ff772015-09-11 15:27:56 -0700800 elif key == "ro.bootimage.build.fingerprint":
801 pieces = value.split("/")
802 pieces[-1] = EditTags(pieces[-1])
803 value = "/".join(pieces)
Doug Zongker17aa9442009-04-17 10:15:58 -0700804 elif key == "ro.build.description":
Doug Zongkerc09abc82010-01-11 13:09:15 -0800805 pieces = value.split(" ")
Stefen Wakefield4260fc12021-03-23 04:58:22 -0500806 assert pieces[-1].endswith("-keys")
Doug Zongkerc09abc82010-01-11 13:09:15 -0800807 pieces[-1] = EditTags(pieces[-1])
808 value = " ".join(pieces)
Magnus Strandh234f4b42019-05-01 23:09:30 +0200809 elif key.startswith("ro.") and key.endswith(".build.tags"):
Doug Zongkerc09abc82010-01-11 13:09:15 -0800810 value = EditTags(value)
Doug Zongkera8608a72013-07-23 11:51:04 -0700811 elif key == "ro.build.display.id":
812 # change, eg, "JWR66N dev-keys" to "JWR66N"
813 value = value.split()
Michael Rungedc2661a2014-06-03 14:43:11 -0700814 if len(value) > 1 and value[-1].endswith("-keys"):
Andrew Boie73d5abb2013-12-11 12:42:03 -0800815 value.pop()
816 value = " ".join(value)
Doug Zongkerc09abc82010-01-11 13:09:15 -0800817 line = key + "=" + value
Doug Zongker17aa9442009-04-17 10:15:58 -0700818 if line != original_line:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800819 print(" replace: ", original_line)
820 print(" with: ", line)
Doug Zongker17aa9442009-04-17 10:15:58 -0700821 output.append(line)
822 return "\n".join(output) + "\n"
823
824
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700825def WriteOtacerts(output_zip, filename, keys):
826 """Constructs a zipfile from given keys; and writes it to output_zip.
827
828 Args:
829 output_zip: The output target_files zip.
830 filename: The archive name in the output zip.
831 keys: A list of public keys to use during OTA package verification.
832 """
Tao Baobb733882019-07-24 23:31:19 -0700833 temp_file = io.BytesIO()
Kelvin Zhang928c2342020-09-22 16:15:57 -0400834 certs_zip = zipfile.ZipFile(temp_file, "w", allowZip64=True)
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700835 for k in keys:
836 common.ZipWrite(certs_zip, k)
837 common.ZipClose(certs_zip)
838 common.ZipWriteStr(output_zip, filename, temp_file.getvalue())
839
840
Doug Zongker831840e2011-09-22 10:28:04 -0700841def ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info):
Doug Zongker8e931bf2009-04-06 15:21:45 -0700842 try:
843 keylist = input_tf_zip.read("META/otakeys.txt").split()
844 except KeyError:
T.R. Fullharta28acc62013-03-18 10:31:26 -0700845 raise common.ExternalError("can't read META/otakeys.txt from input")
Doug Zongker8e931bf2009-04-06 15:21:45 -0700846
Tao Baof718f902017-11-09 10:10:10 -0800847 extra_recovery_keys = misc_info.get("extra_recovery_keys")
Doug Zongkere121d6a2011-02-01 14:13:52 -0800848 if extra_recovery_keys:
849 extra_recovery_keys = [OPTIONS.key_map.get(k, k) + ".x509.pem"
850 for k in extra_recovery_keys.split()]
851 if extra_recovery_keys:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800852 print("extra recovery-only key(s): " + ", ".join(extra_recovery_keys))
Doug Zongkere121d6a2011-02-01 14:13:52 -0800853 else:
854 extra_recovery_keys = []
855
Doug Zongker8e931bf2009-04-06 15:21:45 -0700856 mapped_keys = []
857 for k in keylist:
858 m = re.match(r"^(.*)\.x509\.pem$", k)
859 if not m:
Doug Zongker412c02f2014-02-13 10:58:24 -0800860 raise common.ExternalError(
861 "can't parse \"%s\" from META/otakeys.txt" % (k,))
Doug Zongker8e931bf2009-04-06 15:21:45 -0700862 k = m.group(1)
863 mapped_keys.append(OPTIONS.key_map.get(k, k) + ".x509.pem")
864
Doug Zongkere05628c2009-08-20 17:38:42 -0700865 if mapped_keys:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800866 print("using:\n ", "\n ".join(mapped_keys))
867 print("for OTA package verification")
Doug Zongkere05628c2009-08-20 17:38:42 -0700868 else:
Doug Zongker831840e2011-09-22 10:28:04 -0700869 devkey = misc_info.get("default_system_dev_certificate",
Dan Willemsen0ab1be62019-04-09 21:35:37 -0700870 "build/make/target/product/security/testkey")
Tao Baof718f902017-11-09 10:10:10 -0800871 mapped_devkey = OPTIONS.key_map.get(devkey, devkey)
872 if mapped_devkey != devkey:
873 misc_info["default_system_dev_certificate"] = mapped_devkey
874 mapped_keys.append(mapped_devkey + ".x509.pem")
Tao Baoa80ed222016-06-16 14:41:24 -0700875 print("META/otakeys.txt has no keys; using %s for OTA package"
876 " verification." % (mapped_keys[0],))
Doug Zongker8e931bf2009-04-06 15:21:45 -0700877
Kelvin Zhang9f781ff2021-02-11 19:10:44 -0500878 otacerts = [info
879 for info in input_tf_zip.infolist()
880 if info.filename.endswith("/otacerts.zip")]
881 for info in otacerts:
882 print("Rewriting OTA key:", info.filename, mapped_keys)
883 WriteOtacerts(output_tf_zip, info.filename, mapped_keys)
Doug Zongkereef39442009-04-02 12:14:19 -0700884
Tao Baoa80ed222016-06-16 14:41:24 -0700885
Tao Bao0c28d2d2017-12-24 10:37:38 -0800886def ReplaceVerityPublicKey(output_zip, filename, key_path):
887 """Replaces the verity public key at the given path in the given zip.
888
889 Args:
890 output_zip: The output target_files zip.
891 filename: The archive name in the output zip.
892 key_path: The path to the public key.
893 """
894 print("Replacing verity public key with %s" % (key_path,))
895 common.ZipWrite(output_zip, key_path, arcname=filename)
Geremy Condraf19b3652014-07-29 17:54:54 -0700896
Tao Bao8adcfd12016-06-17 17:01:22 -0700897
Tao Bao46a59992017-06-05 11:55:16 -0700898def ReplaceVerityPrivateKey(misc_info, key_path):
Tao Bao0c28d2d2017-12-24 10:37:38 -0800899 """Replaces the verity private key in misc_info dict.
900
901 Args:
902 misc_info: The info dict.
903 key_path: The path to the private key in PKCS#8 format.
904 """
905 print("Replacing verity private key with %s" % (key_path,))
Andrew Boied083f0b2014-09-15 16:01:07 -0700906 misc_info["verity_key"] = key_path
Doug Zongkereef39442009-04-02 12:14:19 -0700907
Tao Bao8adcfd12016-06-17 17:01:22 -0700908
Tao Baoe838d142017-12-23 23:44:48 -0800909def ReplaceVerityKeyId(input_zip, output_zip, key_path):
910 """Replaces the veritykeyid parameter in BOOT/cmdline.
911
912 Args:
913 input_zip: The input target_files zip, which should be already open.
914 output_zip: The output target_files zip, which should be already open and
915 writable.
916 key_path: The path to the PEM encoded X.509 certificate.
917 """
Tao Baoa3705452019-06-24 15:33:41 -0700918 in_cmdline = input_zip.read("BOOT/cmdline").decode()
Tao Baoe838d142017-12-23 23:44:48 -0800919 # Copy in_cmdline to output_zip if veritykeyid is not present.
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700920 if "veritykeyid" not in in_cmdline:
Tao Baoe838d142017-12-23 23:44:48 -0800921 common.ZipWriteStr(output_zip, "BOOT/cmdline", in_cmdline)
922 return
923
Tao Bao0c28d2d2017-12-24 10:37:38 -0800924 out_buffer = []
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700925 for param in in_cmdline.split():
Tao Baoe838d142017-12-23 23:44:48 -0800926 if "veritykeyid" not in param:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800927 out_buffer.append(param)
Tao Baoe838d142017-12-23 23:44:48 -0800928 continue
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700929
Tao Baoe838d142017-12-23 23:44:48 -0800930 # Extract keyid using openssl command.
931 p = common.Run(["openssl", "x509", "-in", key_path, "-text"],
Tao Baode1d4792018-02-20 10:05:46 -0800932 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
Tao Baoe838d142017-12-23 23:44:48 -0800933 keyid, stderr = p.communicate()
934 assert p.returncode == 0, "Failed to dump certificate: {}".format(stderr)
935 keyid = re.search(
936 r'keyid:([0-9a-fA-F:]*)', keyid).group(1).replace(':', '').lower()
937 print("Replacing verity keyid with {}".format(keyid))
938 out_buffer.append("veritykeyid=id:%s" % (keyid,))
939
940 out_cmdline = ' '.join(out_buffer).strip() + '\n'
941 common.ZipWriteStr(output_zip, "BOOT/cmdline", out_cmdline)
Tao Bao46a59992017-06-05 11:55:16 -0700942
943
944def ReplaceMiscInfoTxt(input_zip, output_zip, misc_info):
945 """Replaces META/misc_info.txt.
946
947 Only writes back the ones in the original META/misc_info.txt. Because the
948 current in-memory dict contains additional items computed at runtime.
949 """
950 misc_info_old = common.LoadDictionaryFromLines(
Tao Baoa3705452019-06-24 15:33:41 -0700951 input_zip.read('META/misc_info.txt').decode().split('\n'))
Tao Bao46a59992017-06-05 11:55:16 -0700952 items = []
953 for key in sorted(misc_info):
954 if key in misc_info_old:
955 items.append('%s=%s' % (key, misc_info[key]))
956 common.ZipWriteStr(output_zip, "META/misc_info.txt", '\n'.join(items))
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700957
Tao Bao8adcfd12016-06-17 17:01:22 -0700958
Tao Bao639118f2017-06-19 15:48:02 -0700959def ReplaceAvbSigningKeys(misc_info):
960 """Replaces the AVB signing keys."""
961
Tao Bao639118f2017-06-19 15:48:02 -0700962 def ReplaceAvbPartitionSigningKey(partition):
963 key = OPTIONS.avb_keys.get(partition)
964 if not key:
965 return
966
967 algorithm = OPTIONS.avb_algorithms.get(partition)
968 assert algorithm, 'Missing AVB signing algorithm for %s' % (partition,)
969
Tao Bao0c28d2d2017-12-24 10:37:38 -0800970 print('Replacing AVB signing key for %s with "%s" (%s)' % (
971 partition, key, algorithm))
Tao Bao639118f2017-06-19 15:48:02 -0700972 misc_info['avb_' + partition + '_algorithm'] = algorithm
973 misc_info['avb_' + partition + '_key_path'] = key
974
975 extra_args = OPTIONS.avb_extra_args.get(partition)
976 if extra_args:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800977 print('Setting extra AVB signing args for %s to "%s"' % (
978 partition, extra_args))
Kelvin Zhang0876c412020-06-23 15:06:58 -0400979 args_key = AVB_FOOTER_ARGS_BY_PARTITION.get(
980 partition,
981 # custom partition
982 "avb_{}_add_hashtree_footer_args".format(partition))
Tao Bao639118f2017-06-19 15:48:02 -0700983 misc_info[args_key] = (misc_info.get(args_key, '') + ' ' + extra_args)
984
985 for partition in AVB_FOOTER_ARGS_BY_PARTITION:
986 ReplaceAvbPartitionSigningKey(partition)
987
Hongguang Chenf23364d2020-04-27 18:36:36 -0700988 for custom_partition in misc_info.get(
989 "avb_custom_images_partition_list", "").strip().split():
990 ReplaceAvbPartitionSigningKey(custom_partition)
991
Tao Bao639118f2017-06-19 15:48:02 -0700992
Tao Bao19b02fe2019-10-09 00:04:28 -0700993def RewriteAvbProps(misc_info):
994 """Rewrites the props in AVB signing args."""
995 for partition, args_key in AVB_FOOTER_ARGS_BY_PARTITION.items():
996 args = misc_info.get(args_key)
997 if not args:
998 continue
999
1000 tokens = []
1001 changed = False
1002 for token in args.split(' '):
1003 fingerprint_key = 'com.android.build.{}.fingerprint'.format(partition)
1004 if not token.startswith(fingerprint_key):
1005 tokens.append(token)
1006 continue
1007 prefix, tag = token.rsplit('/', 1)
1008 tokens.append('{}/{}'.format(prefix, EditTags(tag)))
1009 changed = True
1010
1011 if changed:
1012 result = ' '.join(tokens)
1013 print('Rewriting AVB prop for {}:\n'.format(partition))
1014 print(' replace: {}'.format(args))
1015 print(' with: {}'.format(result))
1016 misc_info[args_key] = result
1017
1018
Bowgo Tsai27c39b02021-03-12 21:40:32 +08001019def ReplaceGkiSigningKey(misc_info):
1020 """Replaces the GKI signing key."""
1021
1022 key = OPTIONS.gki_signing_key
1023 if not key:
1024 return
1025
1026 algorithm = OPTIONS.gki_signing_algorithm
1027 if not algorithm:
1028 raise ValueError("Missing --gki_signing_algorithm")
1029
1030 print('Replacing GKI signing key with "%s" (%s)' % (key, algorithm))
1031 misc_info["gki_signing_algorithm"] = algorithm
1032 misc_info["gki_signing_key_path"] = key
1033
1034 extra_args = OPTIONS.gki_signing_extra_args
1035 if extra_args:
1036 print('Setting extra GKI signing args: "%s"' % (extra_args))
1037 misc_info["gki_signing_signature_args"] = (
1038 misc_info.get("gki_signing_signature_args", '') + ' ' + extra_args)
1039
1040
Doug Zongker831840e2011-09-22 10:28:04 -07001041def BuildKeyMap(misc_info, key_mapping_options):
1042 for s, d in key_mapping_options:
1043 if s is None: # -d option
1044 devkey = misc_info.get("default_system_dev_certificate",
Dan Willemsen0ab1be62019-04-09 21:35:37 -07001045 "build/make/target/product/security/testkey")
Doug Zongker831840e2011-09-22 10:28:04 -07001046 devkeydir = os.path.dirname(devkey)
1047
1048 OPTIONS.key_map.update({
1049 devkeydir + "/testkey": d + "/releasekey",
1050 devkeydir + "/devkey": d + "/releasekey",
1051 devkeydir + "/media": d + "/media",
1052 devkeydir + "/shared": d + "/shared",
1053 devkeydir + "/platform": d + "/platform",
Oleh Cherpak982e6082019-12-10 12:58:54 +02001054 devkeydir + "/networkstack": d + "/networkstack",
Doug Zongker831840e2011-09-22 10:28:04 -07001055 })
1056 else:
1057 OPTIONS.key_map[s] = d
1058
1059
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001060def GetApiLevelAndCodename(input_tf_zip):
Tao Baoa3705452019-06-24 15:33:41 -07001061 data = input_tf_zip.read("SYSTEM/build.prop").decode()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001062 api_level = None
1063 codename = None
1064 for line in data.split("\n"):
1065 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001066 if line and line[0] != '#' and "=" in line:
1067 key, value = line.split("=", 1)
1068 key = key.strip()
1069 if key == "ro.build.version.sdk":
1070 api_level = int(value.strip())
1071 elif key == "ro.build.version.codename":
1072 codename = value.strip()
1073
1074 if api_level is None:
1075 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
1076 if codename is None:
1077 raise ValueError("No ro.build.version.codename in SYSTEM/build.prop")
1078
1079 return (api_level, codename)
1080
1081
1082def GetCodenameToApiLevelMap(input_tf_zip):
Tao Baoa3705452019-06-24 15:33:41 -07001083 data = input_tf_zip.read("SYSTEM/build.prop").decode()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001084 api_level = None
1085 codenames = None
1086 for line in data.split("\n"):
1087 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001088 if line and line[0] != '#' and "=" in line:
1089 key, value = line.split("=", 1)
1090 key = key.strip()
1091 if key == "ro.build.version.sdk":
1092 api_level = int(value.strip())
1093 elif key == "ro.build.version.all_codenames":
1094 codenames = value.strip().split(",")
1095
1096 if api_level is None:
1097 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
1098 if codenames is None:
1099 raise ValueError("No ro.build.version.all_codenames in SYSTEM/build.prop")
1100
Tao Baoa3705452019-06-24 15:33:41 -07001101 result = {}
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001102 for codename in codenames:
1103 codename = codename.strip()
Tao Baobadceb22019-03-15 09:33:43 -07001104 if codename:
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001105 result[codename] = api_level
1106 return result
1107
1108
Tao Baoaa7e9932019-03-15 09:37:01 -07001109def ReadApexKeysInfo(tf_zip):
1110 """Parses the APEX keys info from a given target-files zip.
1111
1112 Given a target-files ZipFile, parses the META/apexkeys.txt entry and returns a
1113 dict that contains the mapping from APEX names (e.g. com.android.tzdata) to a
1114 tuple of (payload_key, container_key).
1115
1116 Args:
1117 tf_zip: The input target_files ZipFile (already open).
1118
1119 Returns:
1120 (payload_key, container_key): payload_key contains the path to the payload
1121 signing key; container_key contains the path to the container signing
1122 key.
1123 """
1124 keys = {}
Tao Baoa3705452019-06-24 15:33:41 -07001125 for line in tf_zip.read('META/apexkeys.txt').decode().split('\n'):
Tao Baoaa7e9932019-03-15 09:37:01 -07001126 line = line.strip()
1127 if not line:
1128 continue
1129 matches = re.match(
1130 r'^name="(?P<NAME>.*)"\s+'
1131 r'public_key="(?P<PAYLOAD_PUBLIC_KEY>.*)"\s+'
1132 r'private_key="(?P<PAYLOAD_PRIVATE_KEY>.*)"\s+'
1133 r'container_certificate="(?P<CONTAINER_CERT>.*)"\s+'
Bill Peckham5c7b0342020-04-03 15:36:23 -07001134 r'container_private_key="(?P<CONTAINER_PRIVATE_KEY>.*?)"'
1135 r'(\s+partition="(?P<PARTITION>.*?)")?$',
Tao Baoaa7e9932019-03-15 09:37:01 -07001136 line)
1137 if not matches:
1138 continue
1139
1140 name = matches.group('NAME')
Tao Baoaa7e9932019-03-15 09:37:01 -07001141 payload_private_key = matches.group("PAYLOAD_PRIVATE_KEY")
1142
1143 def CompareKeys(pubkey, pubkey_suffix, privkey, privkey_suffix):
1144 pubkey_suffix_len = len(pubkey_suffix)
1145 privkey_suffix_len = len(privkey_suffix)
1146 return (pubkey.endswith(pubkey_suffix) and
1147 privkey.endswith(privkey_suffix) and
1148 pubkey[:-pubkey_suffix_len] == privkey[:-privkey_suffix_len])
1149
Ivan Lozanob021b2a2020-07-28 09:31:06 -04001150 # Check the container key names, as we'll carry them without the
Tao Bao6d9e3da2019-03-26 12:59:25 -07001151 # extensions. This doesn't apply to payload keys though, which we will use
1152 # full names only.
Tao Baoaa7e9932019-03-15 09:37:01 -07001153 container_cert = matches.group("CONTAINER_CERT")
1154 container_private_key = matches.group("CONTAINER_PRIVATE_KEY")
Tao Baof454c3a2019-04-24 23:53:42 -07001155 if container_cert == 'PRESIGNED' and container_private_key == 'PRESIGNED':
1156 container_key = 'PRESIGNED'
1157 elif CompareKeys(
Tao Baoaa7e9932019-03-15 09:37:01 -07001158 container_cert, OPTIONS.public_key_suffix,
1159 container_private_key, OPTIONS.private_key_suffix):
Tao Baof454c3a2019-04-24 23:53:42 -07001160 container_key = container_cert[:-len(OPTIONS.public_key_suffix)]
1161 else:
Tao Baoaa7e9932019-03-15 09:37:01 -07001162 raise ValueError("Failed to parse container keys: \n{}".format(line))
1163
Tao Baof454c3a2019-04-24 23:53:42 -07001164 keys[name] = (payload_private_key, container_key)
Tao Baoaa7e9932019-03-15 09:37:01 -07001165
1166 return keys
1167
1168
Doug Zongkereef39442009-04-02 12:14:19 -07001169def main(argv):
1170
Doug Zongker831840e2011-09-22 10:28:04 -07001171 key_mapping_options = []
1172
Doug Zongkereef39442009-04-02 12:14:19 -07001173 def option_handler(o, a):
Doug Zongker05d3dea2009-06-22 11:32:31 -07001174 if o in ("-e", "--extra_apks"):
Doug Zongkereef39442009-04-02 12:14:19 -07001175 names, key = a.split("=")
1176 names = names.split(",")
1177 for n in names:
1178 OPTIONS.extra_apks[n] = key
Tao Baoaa7e9932019-03-15 09:37:01 -07001179 elif o == "--extra_apex_payload_key":
1180 apex_name, key = a.split("=")
1181 OPTIONS.extra_apex_payload_keys[apex_name] = key
Tao Bao93c2a012018-06-19 12:19:35 -07001182 elif o == "--skip_apks_with_path_prefix":
Tianjiea85bdf02020-07-29 11:56:19 -07001183 # Check the prefix, which must be in all upper case.
Tao Bao93c2a012018-06-19 12:19:35 -07001184 prefix = a.split('/')[0]
1185 if not prefix or prefix != prefix.upper():
1186 raise ValueError("Invalid path prefix '%s'" % (a,))
1187 OPTIONS.skip_apks_with_path_prefix.add(a)
Doug Zongkereef39442009-04-02 12:14:19 -07001188 elif o in ("-d", "--default_key_mappings"):
Doug Zongker831840e2011-09-22 10:28:04 -07001189 key_mapping_options.append((None, a))
Doug Zongkereef39442009-04-02 12:14:19 -07001190 elif o in ("-k", "--key_mapping"):
Doug Zongker831840e2011-09-22 10:28:04 -07001191 key_mapping_options.append(a.split("=", 1))
Doug Zongker8e931bf2009-04-06 15:21:45 -07001192 elif o in ("-o", "--replace_ota_keys"):
1193 OPTIONS.replace_ota_keys = True
Doug Zongkerae877012009-04-21 10:04:51 -07001194 elif o in ("-t", "--tag_changes"):
1195 new = []
1196 for i in a.split(","):
1197 i = i.strip()
1198 if not i or i[0] not in "-+":
1199 raise ValueError("Bad tag change '%s'" % (i,))
1200 new.append(i[0] + i[1:].strip())
1201 OPTIONS.tag_changes = tuple(new)
Geremy Condraf19b3652014-07-29 17:54:54 -07001202 elif o == "--replace_verity_public_key":
1203 OPTIONS.replace_verity_public_key = (True, a)
1204 elif o == "--replace_verity_private_key":
1205 OPTIONS.replace_verity_private_key = (True, a)
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001206 elif o == "--replace_verity_keyid":
1207 OPTIONS.replace_verity_keyid = (True, a)
Bowgo Tsai2fe786a2020-02-21 17:48:18 +08001208 elif o == "--remove_avb_public_keys":
1209 OPTIONS.remove_avb_public_keys = a.split(",")
Tao Bao639118f2017-06-19 15:48:02 -07001210 elif o == "--avb_vbmeta_key":
1211 OPTIONS.avb_keys['vbmeta'] = a
1212 elif o == "--avb_vbmeta_algorithm":
1213 OPTIONS.avb_algorithms['vbmeta'] = a
1214 elif o == "--avb_vbmeta_extra_args":
1215 OPTIONS.avb_extra_args['vbmeta'] = a
1216 elif o == "--avb_boot_key":
1217 OPTIONS.avb_keys['boot'] = a
1218 elif o == "--avb_boot_algorithm":
1219 OPTIONS.avb_algorithms['boot'] = a
1220 elif o == "--avb_boot_extra_args":
1221 OPTIONS.avb_extra_args['boot'] = a
1222 elif o == "--avb_dtbo_key":
1223 OPTIONS.avb_keys['dtbo'] = a
1224 elif o == "--avb_dtbo_algorithm":
1225 OPTIONS.avb_algorithms['dtbo'] = a
1226 elif o == "--avb_dtbo_extra_args":
1227 OPTIONS.avb_extra_args['dtbo'] = a
1228 elif o == "--avb_system_key":
1229 OPTIONS.avb_keys['system'] = a
1230 elif o == "--avb_system_algorithm":
1231 OPTIONS.avb_algorithms['system'] = a
1232 elif o == "--avb_system_extra_args":
1233 OPTIONS.avb_extra_args['system'] = a
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001234 elif o == "--avb_system_other_key":
1235 OPTIONS.avb_keys['system_other'] = a
1236 elif o == "--avb_system_other_algorithm":
1237 OPTIONS.avb_algorithms['system_other'] = a
1238 elif o == "--avb_system_other_extra_args":
1239 OPTIONS.avb_extra_args['system_other'] = a
Tao Bao639118f2017-06-19 15:48:02 -07001240 elif o == "--avb_vendor_key":
1241 OPTIONS.avb_keys['vendor'] = a
1242 elif o == "--avb_vendor_algorithm":
1243 OPTIONS.avb_algorithms['vendor'] = a
1244 elif o == "--avb_vendor_extra_args":
1245 OPTIONS.avb_extra_args['vendor'] = a
Tao Baod6085d62019-05-06 12:55:42 -07001246 elif o == "--avb_vbmeta_system_key":
1247 OPTIONS.avb_keys['vbmeta_system'] = a
1248 elif o == "--avb_vbmeta_system_algorithm":
1249 OPTIONS.avb_algorithms['vbmeta_system'] = a
1250 elif o == "--avb_vbmeta_system_extra_args":
1251 OPTIONS.avb_extra_args['vbmeta_system'] = a
1252 elif o == "--avb_vbmeta_vendor_key":
1253 OPTIONS.avb_keys['vbmeta_vendor'] = a
1254 elif o == "--avb_vbmeta_vendor_algorithm":
1255 OPTIONS.avb_algorithms['vbmeta_vendor'] = a
1256 elif o == "--avb_vbmeta_vendor_extra_args":
1257 OPTIONS.avb_extra_args['vbmeta_vendor'] = a
Tao Baoaa7e9932019-03-15 09:37:01 -07001258 elif o == "--avb_apex_extra_args":
1259 OPTIONS.avb_extra_args['apex'] = a
Hongguang Chenf23364d2020-04-27 18:36:36 -07001260 elif o == "--avb_extra_custom_image_key":
1261 partition, key = a.split("=")
1262 OPTIONS.avb_keys[partition] = key
1263 elif o == "--avb_extra_custom_image_algorithm":
1264 partition, algorithm = a.split("=")
1265 OPTIONS.avb_algorithms[partition] = algorithm
1266 elif o == "--avb_extra_custom_image_extra_args":
Hongguang Chen883eecb2020-05-23 22:20:19 -07001267 # Setting the maxsplit parameter to one, which will return a list with
1268 # two elements. e.g., the second '=' should not be splitted for
1269 # 'oem=--signing_helper_with_files=/tmp/avbsigner.sh'.
1270 partition, extra_args = a.split("=", 1)
Hongguang Chenf23364d2020-04-27 18:36:36 -07001271 OPTIONS.avb_extra_args[partition] = extra_args
Bowgo Tsai27c39b02021-03-12 21:40:32 +08001272 elif o == "--gki_signing_key":
1273 OPTIONS.gki_signing_key = a
1274 elif o == "--gki_signing_algorithm":
1275 OPTIONS.gki_signing_algorithm = a
1276 elif o == "--gki_signing_extra_args":
1277 OPTIONS.gki_signing_extra_args = a
Doug Zongkereef39442009-04-02 12:14:19 -07001278 else:
1279 return False
1280 return True
1281
Tao Bao639118f2017-06-19 15:48:02 -07001282 args = common.ParseOptions(
1283 argv, __doc__,
1284 extra_opts="e:d:k:ot:",
1285 extra_long_opts=[
Tao Bao0c28d2d2017-12-24 10:37:38 -08001286 "extra_apks=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001287 "extra_apex_payload_key=",
Tao Bao93c2a012018-06-19 12:19:35 -07001288 "skip_apks_with_path_prefix=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001289 "default_key_mappings=",
1290 "key_mapping=",
1291 "replace_ota_keys",
1292 "tag_changes=",
1293 "replace_verity_public_key=",
1294 "replace_verity_private_key=",
1295 "replace_verity_keyid=",
Bowgo Tsai2fe786a2020-02-21 17:48:18 +08001296 "remove_avb_public_keys=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001297 "avb_apex_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001298 "avb_vbmeta_algorithm=",
1299 "avb_vbmeta_key=",
1300 "avb_vbmeta_extra_args=",
1301 "avb_boot_algorithm=",
1302 "avb_boot_key=",
1303 "avb_boot_extra_args=",
1304 "avb_dtbo_algorithm=",
1305 "avb_dtbo_key=",
1306 "avb_dtbo_extra_args=",
1307 "avb_system_algorithm=",
1308 "avb_system_key=",
1309 "avb_system_extra_args=",
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001310 "avb_system_other_algorithm=",
1311 "avb_system_other_key=",
1312 "avb_system_other_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001313 "avb_vendor_algorithm=",
1314 "avb_vendor_key=",
1315 "avb_vendor_extra_args=",
Tao Baod6085d62019-05-06 12:55:42 -07001316 "avb_vbmeta_system_algorithm=",
1317 "avb_vbmeta_system_key=",
1318 "avb_vbmeta_system_extra_args=",
1319 "avb_vbmeta_vendor_algorithm=",
1320 "avb_vbmeta_vendor_key=",
1321 "avb_vbmeta_vendor_extra_args=",
Hongguang Chenf23364d2020-04-27 18:36:36 -07001322 "avb_extra_custom_image_key=",
1323 "avb_extra_custom_image_algorithm=",
1324 "avb_extra_custom_image_extra_args=",
Bowgo Tsai27c39b02021-03-12 21:40:32 +08001325 "gki_signing_key=",
1326 "gki_signing_algorithm=",
1327 "gki_signing_extra_args=",
Tao Bao639118f2017-06-19 15:48:02 -07001328 ],
1329 extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001330
1331 if len(args) != 2:
1332 common.Usage(__doc__)
1333 sys.exit(1)
1334
Tao Baobadceb22019-03-15 09:33:43 -07001335 common.InitLogging()
1336
Kelvin Zhang928c2342020-09-22 16:15:57 -04001337 input_zip = zipfile.ZipFile(args[0], "r", allowZip64=True)
Tao Bao2b8f4892017-06-13 12:54:58 -07001338 output_zip = zipfile.ZipFile(args[1], "w",
1339 compression=zipfile.ZIP_DEFLATED,
1340 allowZip64=True)
Doug Zongkereef39442009-04-02 12:14:19 -07001341
Doug Zongker831840e2011-09-22 10:28:04 -07001342 misc_info = common.LoadInfoDict(input_zip)
1343
1344 BuildKeyMap(misc_info, key_mapping_options)
1345
Tao Baoaa7e9932019-03-15 09:37:01 -07001346 apk_keys_info, compressed_extension = common.ReadApkCerts(input_zip)
1347 apk_keys = GetApkCerts(apk_keys_info)
Doug Zongkereb338ef2009-05-20 16:50:49 -07001348
Tao Baoaa7e9932019-03-15 09:37:01 -07001349 apex_keys_info = ReadApexKeysInfo(input_zip)
1350 apex_keys = GetApexKeys(apex_keys_info, apk_keys)
1351
Tianjie Xu88a759d2020-01-23 10:47:54 -08001352 # TODO(xunchang) check for the apks inside the apex files, and abort early if
1353 # the keys are not available.
Tao Baoaa7e9932019-03-15 09:37:01 -07001354 CheckApkAndApexKeysAvailable(
1355 input_zip,
1356 set(apk_keys.keys()) | set(apex_keys.keys()),
Tao Baoe1343992019-03-19 12:24:03 -07001357 compressed_extension,
1358 apex_keys)
Tao Baoaa7e9932019-03-15 09:37:01 -07001359
1360 key_passwords = common.GetKeyPasswords(
1361 set(apk_keys.values()) | set(itertools.chain(*apex_keys.values())))
Tao Bao9aa4b9b2016-09-29 17:53:56 -07001362 platform_api_level, _ = GetApiLevelAndCodename(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001363 codename_to_api_level_map = GetCodenameToApiLevelMap(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001364
Doug Zongker412c02f2014-02-13 10:58:24 -08001365 ProcessTargetFiles(input_zip, output_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -07001366 apk_keys, apex_keys, key_passwords,
1367 platform_api_level, codename_to_api_level_map,
Narayan Kamatha07bf042017-08-14 14:49:21 +01001368 compressed_extension)
Doug Zongker8e931bf2009-04-06 15:21:45 -07001369
Tao Bao2ed665a2015-04-01 11:21:55 -07001370 common.ZipClose(input_zip)
1371 common.ZipClose(output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001372
Tianjie Xub48589a2016-08-03 19:21:52 -07001373 # Skip building userdata.img and cache.img when signing the target files.
Tianjie Xu616fbeb2017-05-23 14:51:02 -07001374 new_args = ["--is_signing"]
1375 # add_img_to_target_files builds the system image from scratch, so the
1376 # recovery patch is guaranteed to be regenerated there.
1377 if OPTIONS.rebuild_recovery:
1378 new_args.append("--rebuild_recovery")
1379 new_args.append(args[1])
Tianjie Xub48589a2016-08-03 19:21:52 -07001380 add_img_to_target_files.main(new_args)
Doug Zongker3c84f562014-07-31 11:06:30 -07001381
Tao Bao0c28d2d2017-12-24 10:37:38 -08001382 print("done.")
Doug Zongkereef39442009-04-02 12:14:19 -07001383
1384
1385if __name__ == '__main__':
1386 try:
1387 main(sys.argv[1:])
Tao Bao0c28d2d2017-12-24 10:37:38 -08001388 except common.ExternalError as e:
1389 print("\n ERROR: %s\n" % (e,))
Kelvin Zhang6c17ed32021-04-07 14:56:09 -04001390 raise
Tao Bao639118f2017-06-19 15:48:02 -07001391 finally:
1392 common.Cleanup()