blob: cce771c27a75f2f0829f48fe864a7acdb4e7d3c4 [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
Tao Baod6085d62019-05-06 12:55:42 -070094 --avb_{boot,system,system_other,vendor,dtbo,vbmeta,vbmeta_system,
95 vbmeta_vendor}_algorithm <algorithm>
96 --avb_{boot,system,system_other,vendor,dtbo,vbmeta,vbmeta_system,
97 vbmeta_vendor}_key <key>
Tao Bao639118f2017-06-19 15:48:02 -070098 Use the specified algorithm (e.g. SHA256_RSA4096) and the key to AVB-sign
99 the specified image. Otherwise it uses the existing values in info dict.
100
Tao Baod6085d62019-05-06 12:55:42 -0700101 --avb_{apex,boot,system,system_other,vendor,dtbo,vbmeta,vbmeta_system,
102 vbmeta_vendor}_extra_args <args>
Tao Bao639118f2017-06-19 15:48:02 -0700103 Specify any additional args that are needed to AVB-sign the image
104 (e.g. "--signing_helper /path/to/helper"). The args will be appended to
105 the existing ones in info dict.
Tianjie Xu88a759d2020-01-23 10:47:54 -0800106
107 --android_jar_path <path>
108 Path to the android.jar to repack the apex file.
Doug Zongkereef39442009-04-02 12:14:19 -0700109"""
110
Tao Bao0c28d2d2017-12-24 10:37:38 -0800111from __future__ import print_function
Doug Zongkereef39442009-04-02 12:14:19 -0700112
Robert Craig817c5742013-04-19 10:59:22 -0400113import base64
Doug Zongker8e931bf2009-04-06 15:21:45 -0700114import copy
Robert Craig817c5742013-04-19 10:59:22 -0400115import errno
Narayan Kamatha07bf042017-08-14 14:49:21 +0100116import gzip
Tao Baobb733882019-07-24 23:31:19 -0700117import io
Tao Baoaa7e9932019-03-15 09:37:01 -0700118import itertools
Tao Baobadceb22019-03-15 09:33:43 -0700119import logging
Doug Zongkereef39442009-04-02 12:14:19 -0700120import os
121import re
Narayan Kamatha07bf042017-08-14 14:49:21 +0100122import shutil
Tao Bao9fdd00f2017-07-12 11:57:05 -0700123import stat
Doug Zongkereef39442009-04-02 12:14:19 -0700124import subprocess
Tao Bao0c28d2d2017-12-24 10:37:38 -0800125import sys
Doug Zongkereef39442009-04-02 12:14:19 -0700126import tempfile
127import zipfile
Tao Bao66472632017-12-04 17:16:36 -0800128from xml.etree import ElementTree
Doug Zongkereef39442009-04-02 12:14:19 -0700129
Doug Zongker3c84f562014-07-31 11:06:30 -0700130import add_img_to_target_files
Tao Baoaa7e9932019-03-15 09:37:01 -0700131import apex_utils
Doug Zongkereef39442009-04-02 12:14:19 -0700132import common
133
Tao Bao0c28d2d2017-12-24 10:37:38 -0800134
135if sys.hexversion < 0x02070000:
136 print("Python 2.7 or newer is required.", file=sys.stderr)
137 sys.exit(1)
138
139
Tao Baobadceb22019-03-15 09:33:43 -0700140logger = logging.getLogger(__name__)
141
Doug Zongkereef39442009-04-02 12:14:19 -0700142OPTIONS = common.OPTIONS
143
144OPTIONS.extra_apks = {}
Tao Baoaa7e9932019-03-15 09:37:01 -0700145OPTIONS.extra_apex_payload_keys = {}
Tao Bao93c2a012018-06-19 12:19:35 -0700146OPTIONS.skip_apks_with_path_prefix = set()
Doug Zongkereef39442009-04-02 12:14:19 -0700147OPTIONS.key_map = {}
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700148OPTIONS.rebuild_recovery = False
Doug Zongker8e931bf2009-04-06 15:21:45 -0700149OPTIONS.replace_ota_keys = False
Geremy Condraf19b3652014-07-29 17:54:54 -0700150OPTIONS.replace_verity_public_key = False
151OPTIONS.replace_verity_private_key = False
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700152OPTIONS.replace_verity_keyid = False
Doug Zongker831840e2011-09-22 10:28:04 -0700153OPTIONS.tag_changes = ("-test-keys", "-dev-keys", "+release-keys")
Tao Bao639118f2017-06-19 15:48:02 -0700154OPTIONS.avb_keys = {}
155OPTIONS.avb_algorithms = {}
156OPTIONS.avb_extra_args = {}
Tianjie Xu88a759d2020-01-23 10:47:54 -0800157OPTIONS.android_jar_path = None
Doug Zongkereef39442009-04-02 12:14:19 -0700158
Tao Bao0c28d2d2017-12-24 10:37:38 -0800159
Tao Bao19b02fe2019-10-09 00:04:28 -0700160AVB_FOOTER_ARGS_BY_PARTITION = {
161 'boot' : 'avb_boot_add_hash_footer_args',
162 'dtbo' : 'avb_dtbo_add_hash_footer_args',
163 'recovery' : 'avb_recovery_add_hash_footer_args',
164 'system' : 'avb_system_add_hashtree_footer_args',
165 'system_other' : 'avb_system_other_add_hashtree_footer_args',
166 'vendor' : 'avb_vendor_add_hashtree_footer_args',
167 'vendor_boot' : 'avb_vendor_boot_add_hash_footer_args',
168 'vbmeta' : 'avb_vbmeta_args',
169 'vbmeta_system' : 'avb_vbmeta_system_args',
170 'vbmeta_vendor' : 'avb_vbmeta_vendor_args',
171}
172
173
Narayan Kamatha07bf042017-08-14 14:49:21 +0100174def GetApkCerts(certmap):
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800175 # apply the key remapping to the contents of the file
Tao Baoa3705452019-06-24 15:33:41 -0700176 for apk, cert in certmap.items():
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800177 certmap[apk] = OPTIONS.key_map.get(cert, cert)
178
179 # apply all the -e options, overriding anything in the file
Tao Baoa3705452019-06-24 15:33:41 -0700180 for apk, cert in OPTIONS.extra_apks.items():
Doug Zongkerdecf9952009-12-15 17:27:49 -0800181 if not cert:
182 cert = "PRESIGNED"
Doug Zongkerad88c7c2009-04-14 12:34:27 -0700183 certmap[apk] = OPTIONS.key_map.get(cert, cert)
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800184
Doug Zongkereef39442009-04-02 12:14:19 -0700185 return certmap
186
187
Tao Baoaa7e9932019-03-15 09:37:01 -0700188def GetApexKeys(keys_info, key_map):
189 """Gets APEX payload and container signing keys by applying the mapping rules.
190
Tao Baoe1343992019-03-19 12:24:03 -0700191 Presigned payload / container keys will be set accordingly.
Tao Baoaa7e9932019-03-15 09:37:01 -0700192
193 Args:
194 keys_info: A dict that maps from APEX filenames to a tuple of (payload_key,
195 container_key).
196 key_map: A dict that overrides the keys, specified via command-line input.
197
198 Returns:
199 A dict that contains the updated APEX key mapping, which should be used for
200 the current signing.
Tao Baof98fa102019-04-24 14:51:25 -0700201
202 Raises:
203 AssertionError: On invalid container / payload key overrides.
Tao Baoaa7e9932019-03-15 09:37:01 -0700204 """
205 # Apply all the --extra_apex_payload_key options to override the payload
206 # signing keys in the given keys_info.
207 for apex, key in OPTIONS.extra_apex_payload_keys.items():
Tao Baoe1343992019-03-19 12:24:03 -0700208 if not key:
209 key = 'PRESIGNED'
Tao Bao34223092019-07-11 11:52:52 -0700210 if apex not in keys_info:
211 logger.warning('Failed to find %s in target_files; Ignored', apex)
212 continue
Tao Baoaa7e9932019-03-15 09:37:01 -0700213 keys_info[apex] = (key, keys_info[apex][1])
214
215 # Apply the key remapping to container keys.
216 for apex, (payload_key, container_key) in keys_info.items():
217 keys_info[apex] = (payload_key, key_map.get(container_key, container_key))
218
219 # Apply all the --extra_apks options to override the container keys.
220 for apex, key in OPTIONS.extra_apks.items():
221 # Skip non-APEX containers.
222 if apex not in keys_info:
223 continue
Tao Baoe1343992019-03-19 12:24:03 -0700224 if not key:
225 key = 'PRESIGNED'
Tao Baofa9de0a2019-03-18 10:24:17 -0700226 keys_info[apex] = (keys_info[apex][0], key_map.get(key, key))
Tao Baoaa7e9932019-03-15 09:37:01 -0700227
Tao Baof98fa102019-04-24 14:51:25 -0700228 # A PRESIGNED container entails a PRESIGNED payload. Apply this to all the
229 # APEX key pairs. However, a PRESIGNED container with non-PRESIGNED payload
230 # (overridden via commandline) indicates a config error, which should not be
231 # allowed.
232 for apex, (payload_key, container_key) in keys_info.items():
233 if container_key != 'PRESIGNED':
234 continue
235 if apex in OPTIONS.extra_apex_payload_keys:
236 payload_override = OPTIONS.extra_apex_payload_keys[apex]
237 assert payload_override == '', \
238 ("Invalid APEX key overrides: {} has PRESIGNED container but "
239 "non-PRESIGNED payload key {}").format(apex, payload_override)
240 if payload_key != 'PRESIGNED':
241 print(
242 "Setting {} payload as PRESIGNED due to PRESIGNED container".format(
243 apex))
244 keys_info[apex] = ('PRESIGNED', 'PRESIGNED')
245
Tao Baoaa7e9932019-03-15 09:37:01 -0700246 return keys_info
247
248
Tao Bao93c2a012018-06-19 12:19:35 -0700249def GetApkFileInfo(filename, compressed_extension, skipped_prefixes):
Tao Bao11f955c2018-06-19 12:19:35 -0700250 """Returns the APK info based on the given filename.
251
252 Checks if the given filename (with path) looks like an APK file, by taking the
Tao Bao93c2a012018-06-19 12:19:35 -0700253 compressed extension into consideration. If it appears to be an APK file,
254 further checks if the APK file should be skipped when signing, based on the
255 given path prefixes.
Tao Bao11f955c2018-06-19 12:19:35 -0700256
257 Args:
258 filename: Path to the file.
259 compressed_extension: The extension string of compressed APKs (e.g. ".gz"),
260 or None if there's no compressed APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700261 skipped_prefixes: A set/list/tuple of the path prefixes to be skipped.
Tao Bao11f955c2018-06-19 12:19:35 -0700262
263 Returns:
Tao Bao93c2a012018-06-19 12:19:35 -0700264 (is_apk, is_compressed, should_be_skipped): is_apk indicates whether the
265 given filename is an APK file. is_compressed indicates whether the APK file
266 is compressed (only meaningful when is_apk is True). should_be_skipped
267 indicates whether the filename matches any of the given prefixes to be
268 skipped.
Tao Bao11f955c2018-06-19 12:19:35 -0700269
270 Raises:
Tao Bao93c2a012018-06-19 12:19:35 -0700271 AssertionError: On invalid compressed_extension or skipped_prefixes inputs.
Tao Bao11f955c2018-06-19 12:19:35 -0700272 """
273 assert compressed_extension is None or compressed_extension.startswith('.'), \
274 "Invalid compressed_extension arg: '{}'".format(compressed_extension)
275
Tao Bao93c2a012018-06-19 12:19:35 -0700276 # skipped_prefixes should be one of set/list/tuple types. Other types such as
277 # str shouldn't be accepted.
Tao Baobadceb22019-03-15 09:33:43 -0700278 assert isinstance(skipped_prefixes, (set, list, tuple)), \
279 "Invalid skipped_prefixes input type: {}".format(type(skipped_prefixes))
Tao Bao93c2a012018-06-19 12:19:35 -0700280
Tao Bao11f955c2018-06-19 12:19:35 -0700281 compressed_apk_extension = (
282 ".apk" + compressed_extension if compressed_extension else None)
283 is_apk = (filename.endswith(".apk") or
284 (compressed_apk_extension and
285 filename.endswith(compressed_apk_extension)))
286 if not is_apk:
Tao Bao93c2a012018-06-19 12:19:35 -0700287 return (False, False, False)
Tao Bao11f955c2018-06-19 12:19:35 -0700288
289 is_compressed = (compressed_apk_extension and
290 filename.endswith(compressed_apk_extension))
Tao Bao93c2a012018-06-19 12:19:35 -0700291 should_be_skipped = filename.startswith(tuple(skipped_prefixes))
292 return (True, is_compressed, should_be_skipped)
Tao Bao11f955c2018-06-19 12:19:35 -0700293
294
Tao Baoaa7e9932019-03-15 09:37:01 -0700295def CheckApkAndApexKeysAvailable(input_tf_zip, known_keys,
Tao Baoe1343992019-03-19 12:24:03 -0700296 compressed_extension, apex_keys):
Tao Baoaa7e9932019-03-15 09:37:01 -0700297 """Checks that all the APKs and APEXes have keys specified.
Tao Bao11f955c2018-06-19 12:19:35 -0700298
299 Args:
300 input_tf_zip: An open target_files zip file.
Tao Baoaa7e9932019-03-15 09:37:01 -0700301 known_keys: A set of APKs and APEXes that have known signing keys.
Tao Bao11f955c2018-06-19 12:19:35 -0700302 compressed_extension: The extension string of compressed APKs, such as
Tao Baoaa7e9932019-03-15 09:37:01 -0700303 '.gz', or None if there's no compressed APKs.
Tao Baoe1343992019-03-19 12:24:03 -0700304 apex_keys: A dict that contains the key mapping from APEX name to
305 (payload_key, container_key).
Tao Bao11f955c2018-06-19 12:19:35 -0700306
307 Raises:
Tao Baoaa7e9932019-03-15 09:37:01 -0700308 AssertionError: On finding unknown APKs and APEXes.
Tao Bao11f955c2018-06-19 12:19:35 -0700309 """
Tao Baoaa7e9932019-03-15 09:37:01 -0700310 unknown_files = []
Doug Zongkereb338ef2009-05-20 16:50:49 -0700311 for info in input_tf_zip.infolist():
Tao Baoaa7e9932019-03-15 09:37:01 -0700312 # Handle APEXes first, e.g. SYSTEM/apex/com.android.tzdata.apex.
313 if (info.filename.startswith('SYSTEM/apex') and
314 info.filename.endswith('.apex')):
315 name = os.path.basename(info.filename)
316 if name not in known_keys:
317 unknown_files.append(name)
318 continue
319
320 # And APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700321 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
322 info.filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
323 if not is_apk or should_be_skipped:
Tao Bao11f955c2018-06-19 12:19:35 -0700324 continue
Tao Baoaa7e9932019-03-15 09:37:01 -0700325
Tao Bao11f955c2018-06-19 12:19:35 -0700326 name = os.path.basename(info.filename)
327 if is_compressed:
328 name = name[:-len(compressed_extension)]
Tao Baoaa7e9932019-03-15 09:37:01 -0700329 if name not in known_keys:
330 unknown_files.append(name)
Tao Bao11f955c2018-06-19 12:19:35 -0700331
Tao Baoaa7e9932019-03-15 09:37:01 -0700332 assert not unknown_files, \
Tao Bao11f955c2018-06-19 12:19:35 -0700333 ("No key specified for:\n {}\n"
334 "Use '-e <apkname>=' to specify a key (which may be an empty string to "
Tao Baoaa7e9932019-03-15 09:37:01 -0700335 "not sign this apk).".format("\n ".join(unknown_files)))
Doug Zongkereb338ef2009-05-20 16:50:49 -0700336
Tao Baoe1343992019-03-19 12:24:03 -0700337 # For all the APEXes, double check that we won't have an APEX that has only
Tao Baof98fa102019-04-24 14:51:25 -0700338 # one of the payload / container keys set. Note that non-PRESIGNED container
339 # with PRESIGNED payload could be allowed but currently unsupported. It would
340 # require changing SignApex implementation.
Tao Baoe1343992019-03-19 12:24:03 -0700341 if not apex_keys:
342 return
343
344 invalid_apexes = []
345 for info in input_tf_zip.infolist():
346 if (not info.filename.startswith('SYSTEM/apex') or
347 not info.filename.endswith('.apex')):
348 continue
349
350 name = os.path.basename(info.filename)
351 (payload_key, container_key) = apex_keys[name]
352 if ((payload_key in common.SPECIAL_CERT_STRINGS and
353 container_key not in common.SPECIAL_CERT_STRINGS) or
354 (payload_key not in common.SPECIAL_CERT_STRINGS and
355 container_key in common.SPECIAL_CERT_STRINGS)):
356 invalid_apexes.append(
357 "{}: payload_key {}, container_key {}".format(
358 name, payload_key, container_key))
359
360 assert not invalid_apexes, \
361 "Invalid APEX keys specified:\n {}\n".format(
362 "\n ".join(invalid_apexes))
363
Doug Zongkereb338ef2009-05-20 16:50:49 -0700364
Narayan Kamatha07bf042017-08-14 14:49:21 +0100365def SignApk(data, keyname, pw, platform_api_level, codename_to_api_level_map,
366 is_compressed):
Doug Zongkereef39442009-04-02 12:14:19 -0700367 unsigned = tempfile.NamedTemporaryFile()
368 unsigned.write(data)
369 unsigned.flush()
370
Narayan Kamatha07bf042017-08-14 14:49:21 +0100371 if is_compressed:
372 uncompressed = tempfile.NamedTemporaryFile()
Tao Bao0c28d2d2017-12-24 10:37:38 -0800373 with gzip.open(unsigned.name, "rb") as in_file, \
374 open(uncompressed.name, "wb") as out_file:
Narayan Kamatha07bf042017-08-14 14:49:21 +0100375 shutil.copyfileobj(in_file, out_file)
376
377 # Finally, close the "unsigned" file (which is gzip compressed), and then
378 # replace it with the uncompressed version.
379 #
380 # TODO(narayan): All this nastiness can be avoided if python 3.2 is in use,
381 # we could just gzip / gunzip in-memory buffers instead.
382 unsigned.close()
383 unsigned = uncompressed
384
Doug Zongkereef39442009-04-02 12:14:19 -0700385 signed = tempfile.NamedTemporaryFile()
386
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800387 # For pre-N builds, don't upgrade to SHA-256 JAR signatures based on the APK's
388 # minSdkVersion to avoid increasing incremental OTA update sizes. If an APK
389 # didn't change, we don't want its signature to change due to the switch
390 # from SHA-1 to SHA-256.
391 # By default, APK signer chooses SHA-256 signatures if the APK's minSdkVersion
392 # is 18 or higher. For pre-N builds we disable this mechanism by pretending
393 # that the APK's minSdkVersion is 1.
394 # For N+ builds, we let APK signer rely on the APK's minSdkVersion to
395 # determine whether to use SHA-256.
396 min_api_level = None
397 if platform_api_level > 23:
398 # Let APK signer choose whether to use SHA-1 or SHA-256, based on the APK's
399 # minSdkVersion attribute
400 min_api_level = None
401 else:
402 # Force APK signer to use SHA-1
403 min_api_level = 1
404
405 common.SignFile(unsigned.name, signed.name, keyname, pw,
Tao Bao0c28d2d2017-12-24 10:37:38 -0800406 min_api_level=min_api_level,
407 codename_to_api_level_map=codename_to_api_level_map)
Doug Zongkereef39442009-04-02 12:14:19 -0700408
Tao Bao0c28d2d2017-12-24 10:37:38 -0800409 data = None
Narayan Kamatha07bf042017-08-14 14:49:21 +0100410 if is_compressed:
411 # Recompress the file after it has been signed.
412 compressed = tempfile.NamedTemporaryFile()
Tao Bao0c28d2d2017-12-24 10:37:38 -0800413 with open(signed.name, "rb") as in_file, \
414 gzip.open(compressed.name, "wb") as out_file:
Narayan Kamatha07bf042017-08-14 14:49:21 +0100415 shutil.copyfileobj(in_file, out_file)
416
417 data = compressed.read()
418 compressed.close()
419 else:
420 data = signed.read()
421
Doug Zongkereef39442009-04-02 12:14:19 -0700422 unsigned.close()
423 signed.close()
424
425 return data
426
427
Doug Zongker412c02f2014-02-13 10:58:24 -0800428def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -0700429 apk_keys, apex_keys, key_passwords,
430 platform_api_level, codename_to_api_level_map,
Narayan Kamatha07bf042017-08-14 14:49:21 +0100431 compressed_extension):
Tao Bao93c2a012018-06-19 12:19:35 -0700432 # maxsize measures the maximum filename length, including the ones to be
433 # skipped.
Tao Bao0c28d2d2017-12-24 10:37:38 -0800434 maxsize = max(
435 [len(os.path.basename(i.filename)) for i in input_tf_zip.infolist()
Tao Bao93c2a012018-06-19 12:19:35 -0700436 if GetApkFileInfo(i.filename, compressed_extension, [])[0]])
Tao Baoa80ed222016-06-16 14:41:24 -0700437 system_root_image = misc_info.get("system_root_image") == "true"
Doug Zongker412c02f2014-02-13 10:58:24 -0800438
Doug Zongkereef39442009-04-02 12:14:19 -0700439 for info in input_tf_zip.infolist():
Tao Bao11f955c2018-06-19 12:19:35 -0700440 filename = info.filename
441 if filename.startswith("IMAGES/"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700442 continue
Doug Zongker3c84f562014-07-31 11:06:30 -0700443
Tao Bao04808502019-07-25 23:11:41 -0700444 # Skip OTA-specific images (e.g. split super images), which will be
445 # re-generated during signing.
Tao Bao33bf2682019-01-11 12:37:35 -0800446 if filename.startswith("OTA/") and filename.endswith(".img"):
447 continue
448
Tao Bao11f955c2018-06-19 12:19:35 -0700449 data = input_tf_zip.read(filename)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700450 out_info = copy.copy(info)
Tao Bao93c2a012018-06-19 12:19:35 -0700451 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
452 filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
453
454 if is_apk and should_be_skipped:
455 # Copy skipped APKs verbatim.
456 print(
457 "NOT signing: %s\n"
458 " (skipped due to matching prefix)" % (filename,))
459 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker412c02f2014-02-13 10:58:24 -0800460
Tao Baof2cffbd2015-07-22 12:33:18 -0700461 # Sign APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700462 elif is_apk:
Tao Bao11f955c2018-06-19 12:19:35 -0700463 name = os.path.basename(filename)
Narayan Kamatha07bf042017-08-14 14:49:21 +0100464 if is_compressed:
465 name = name[:-len(compressed_extension)]
466
Tao Baoaa7e9932019-03-15 09:37:01 -0700467 key = apk_keys[name]
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800468 if key not in common.SPECIAL_CERT_STRINGS:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800469 print(" signing: %-*s (%s)" % (maxsize, name, key))
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800470 signed_data = SignApk(data, key, key_passwords[key], platform_api_level,
Tao Bao0c28d2d2017-12-24 10:37:38 -0800471 codename_to_api_level_map, is_compressed)
Tao Bao2ed665a2015-04-01 11:21:55 -0700472 common.ZipWriteStr(output_tf_zip, out_info, signed_data)
Doug Zongkereef39442009-04-02 12:14:19 -0700473 else:
474 # an APK we're not supposed to sign.
Tao Bao93c2a012018-06-19 12:19:35 -0700475 print(
476 "NOT signing: %s\n"
477 " (skipped due to special cert string)" % (name,))
Tao Bao2ed665a2015-04-01 11:21:55 -0700478 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoa80ed222016-06-16 14:41:24 -0700479
Tao Baoaa7e9932019-03-15 09:37:01 -0700480 # Sign bundled APEX files.
481 elif filename.startswith("SYSTEM/apex") and filename.endswith(".apex"):
482 name = os.path.basename(filename)
483 payload_key, container_key = apex_keys[name]
484
Tao Baoe1343992019-03-19 12:24:03 -0700485 # We've asserted not having a case with only one of them PRESIGNED.
486 if (payload_key not in common.SPECIAL_CERT_STRINGS and
487 container_key not in common.SPECIAL_CERT_STRINGS):
488 print(" signing: %-*s container (%s)" % (
489 maxsize, name, container_key))
490 print(" : %-*s payload (%s)" % (
491 maxsize, name, payload_key))
Tao Baoaa7e9932019-03-15 09:37:01 -0700492
Tao Baoe7354ba2019-05-09 16:54:15 -0700493 signed_apex = apex_utils.SignApex(
Tao Bao1ac886e2019-06-26 11:58:22 -0700494 misc_info['avb_avbtool'],
Tao Baoe1343992019-03-19 12:24:03 -0700495 data,
496 payload_key,
497 container_key,
498 key_passwords[container_key],
Tianjie Xu88a759d2020-01-23 10:47:54 -0800499 apk_keys,
Tao Baoe1343992019-03-19 12:24:03 -0700500 codename_to_api_level_map,
Tao Bao448004a2019-09-19 07:55:02 -0700501 no_hashtree=True,
502 signing_args=OPTIONS.avb_extra_args.get('apex'))
Tao Baoe1343992019-03-19 12:24:03 -0700503 common.ZipWrite(output_tf_zip, signed_apex, filename)
Tao Baoaa7e9932019-03-15 09:37:01 -0700504
Tao Baoe1343992019-03-19 12:24:03 -0700505 else:
506 print(
507 "NOT signing: %s\n"
508 " (skipped due to special cert string)" % (name,))
509 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoaa7e9932019-03-15 09:37:01 -0700510
511 # AVB public keys for the installed APEXes, which will be updated later.
512 elif (os.path.dirname(filename) == 'SYSTEM/etc/security/apex' and
513 filename != 'SYSTEM/etc/security/apex/'):
514 continue
515
Tao Baoa80ed222016-06-16 14:41:24 -0700516 # System properties.
Tao Bao338c1b72019-06-21 09:38:24 -0700517 elif filename in (
518 "SYSTEM/build.prop",
519
520 "VENDOR/build.prop",
521 "SYSTEM/vendor/build.prop",
522
523 "ODM/etc/build.prop",
524 "VENDOR/odm/etc/build.prop",
525
526 "PRODUCT/build.prop",
527 "SYSTEM/product/build.prop",
528
Justin Yun6151e3f2019-06-25 15:58:13 +0900529 "SYSTEM_EXT/build.prop",
530 "SYSTEM/system_ext/build.prop",
Tao Bao338c1b72019-06-21 09:38:24 -0700531
532 "SYSTEM/etc/prop.default",
533 "BOOT/RAMDISK/prop.default",
534 "RECOVERY/RAMDISK/prop.default",
535
536 # ROOT/default.prop is a legacy path, but may still exist for upgrading
537 # devices that don't support `property_overrides_split_enabled`.
538 "ROOT/default.prop",
539
540 # RECOVERY/RAMDISK/default.prop is a legacy path, but will always exist
541 # as a symlink in the current code. So it's a no-op here. Keeping the
542 # path here for clarity.
543 "RECOVERY/RAMDISK/default.prop"):
Tao Bao11f955c2018-06-19 12:19:35 -0700544 print("Rewriting %s:" % (filename,))
Hung-ying Tyan7eb6a922017-05-01 21:56:26 +0800545 if stat.S_ISLNK(info.external_attr >> 16):
546 new_data = data
547 else:
Tao Baoa3705452019-06-24 15:33:41 -0700548 new_data = RewriteProps(data.decode())
Tao Bao2ed665a2015-04-01 11:21:55 -0700549 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700550
Tao Bao66472632017-12-04 17:16:36 -0800551 # Replace the certs in *mac_permissions.xml (there could be multiple, such
552 # as {system,vendor}/etc/selinux/{plat,nonplat}_mac_permissions.xml).
Tao Bao11f955c2018-06-19 12:19:35 -0700553 elif filename.endswith("mac_permissions.xml"):
554 print("Rewriting %s with new keys." % (filename,))
Tao Baoa3705452019-06-24 15:33:41 -0700555 new_data = ReplaceCerts(data.decode())
Tao Bao2ed665a2015-04-01 11:21:55 -0700556 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700557
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700558 # Ask add_img_to_target_files to rebuild the recovery patch if needed.
Tao Bao11f955c2018-06-19 12:19:35 -0700559 elif filename in ("SYSTEM/recovery-from-boot.p",
Robin Leeda427de2020-01-03 19:16:32 +0100560 "VENDOR/recovery-from-boot.p",
561
Tao Bao11f955c2018-06-19 12:19:35 -0700562 "SYSTEM/etc/recovery.img",
Robin Leeda427de2020-01-03 19:16:32 +0100563 "VENDOR/etc/recovery.img",
564
565 "SYSTEM/bin/install-recovery.sh",
566 "VENDOR/bin/install-recovery.sh"):
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700567 OPTIONS.rebuild_recovery = True
Tao Baoa80ed222016-06-16 14:41:24 -0700568
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700569 # Don't copy OTA certs if we're replacing them.
Tianjie Xu2df23d72019-10-15 18:06:25 -0700570 # Replacement of update-payload-key.pub.pem was removed in b/116660991.
Tao Bao696bb332018-08-17 16:27:01 -0700571 elif (
572 OPTIONS.replace_ota_keys and
573 filename in (
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700574 "BOOT/RAMDISK/system/etc/security/otacerts.zip",
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700575 "RECOVERY/RAMDISK/system/etc/security/otacerts.zip",
Tianjie Xu2df23d72019-10-15 18:06:25 -0700576 "SYSTEM/etc/security/otacerts.zip")):
Doug Zongker412c02f2014-02-13 10:58:24 -0800577 pass
Tao Baoa80ed222016-06-16 14:41:24 -0700578
Tao Bao46a59992017-06-05 11:55:16 -0700579 # Skip META/misc_info.txt since we will write back the new values later.
Tao Bao11f955c2018-06-19 12:19:35 -0700580 elif filename == "META/misc_info.txt":
Geremy Condraf19b3652014-07-29 17:54:54 -0700581 pass
Tao Bao8adcfd12016-06-17 17:01:22 -0700582
583 # Skip verity public key if we will replace it.
Michael Runge947894f2014-10-14 20:58:38 -0700584 elif (OPTIONS.replace_verity_public_key and
Tao Bao11f955c2018-06-19 12:19:35 -0700585 filename in ("BOOT/RAMDISK/verity_key",
586 "ROOT/verity_key")):
Geremy Condraf19b3652014-07-29 17:54:54 -0700587 pass
Tao Baoa80ed222016-06-16 14:41:24 -0700588
Tao Bao8adcfd12016-06-17 17:01:22 -0700589 # Skip verity keyid (for system_root_image use) if we will replace it.
Tao Bao11f955c2018-06-19 12:19:35 -0700590 elif OPTIONS.replace_verity_keyid and filename == "BOOT/cmdline":
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700591 pass
592
Tianjie Xu4f099002016-08-11 18:04:27 -0700593 # Skip the care_map as we will regenerate the system/vendor images.
Tianjie Xu4c05f4a2018-09-14 16:24:41 -0700594 elif filename == "META/care_map.pb" or filename == "META/care_map.txt":
Tianjie Xu4f099002016-08-11 18:04:27 -0700595 pass
596
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800597 # Updates system_other.avbpubkey in /product/etc/.
598 elif filename in (
599 "PRODUCT/etc/security/avb/system_other.avbpubkey",
600 "SYSTEM/product/etc/security/avb/system_other.avbpubkey"):
601 # Only update system_other's public key, if the corresponding signing
602 # key is specified via --avb_system_other_key.
603 signing_key = OPTIONS.avb_keys.get("system_other")
604 if signing_key:
Tao Bao1ac886e2019-06-26 11:58:22 -0700605 public_key = common.ExtractAvbPublicKey(
606 misc_info['avb_avbtool'], signing_key)
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800607 print(" Rewriting AVB public key of system_other in /product")
608 common.ZipWrite(output_tf_zip, public_key, filename)
609
Bowgo Tsai78369eb2019-04-23 12:28:44 +0800610 # Should NOT sign boot-debug.img.
611 elif filename in (
612 "BOOT/RAMDISK/force_debuggable",
613 "RECOVERY/RAMDISK/force_debuggable"
614 "RECOVERY/RAMDISK/first_stage_ramdisk/force_debuggable"):
615 raise common.ExternalError("debuggable boot.img cannot be signed")
616
Tao Baoa80ed222016-06-16 14:41:24 -0700617 # A non-APK file; copy it verbatim.
Doug Zongkereef39442009-04-02 12:14:19 -0700618 else:
Tao Bao2ed665a2015-04-01 11:21:55 -0700619 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700620
Doug Zongker412c02f2014-02-13 10:58:24 -0800621 if OPTIONS.replace_ota_keys:
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700622 ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info)
Doug Zongker412c02f2014-02-13 10:58:24 -0800623
Tao Bao46a59992017-06-05 11:55:16 -0700624 # Replace the keyid string in misc_info dict.
Tao Bao8adcfd12016-06-17 17:01:22 -0700625 if OPTIONS.replace_verity_private_key:
Tao Bao46a59992017-06-05 11:55:16 -0700626 ReplaceVerityPrivateKey(misc_info, OPTIONS.replace_verity_private_key[1])
Tao Bao8adcfd12016-06-17 17:01:22 -0700627
628 if OPTIONS.replace_verity_public_key:
Tao Baoc9981932019-09-16 12:10:43 -0700629 # Replace the one in root dir in system.img.
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700630 ReplaceVerityPublicKey(
Tao Baoc9981932019-09-16 12:10:43 -0700631 output_tf_zip, 'ROOT/verity_key', OPTIONS.replace_verity_public_key[1])
632
633 if not system_root_image:
634 # Additionally replace the copy in ramdisk if not using system-as-root.
635 ReplaceVerityPublicKey(
636 output_tf_zip,
637 'BOOT/RAMDISK/verity_key',
638 OPTIONS.replace_verity_public_key[1])
Tao Bao8adcfd12016-06-17 17:01:22 -0700639
640 # Replace the keyid string in BOOT/cmdline.
641 if OPTIONS.replace_verity_keyid:
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700642 ReplaceVerityKeyId(input_tf_zip, output_tf_zip,
643 OPTIONS.replace_verity_keyid[1])
Doug Zongker412c02f2014-02-13 10:58:24 -0800644
Tao Bao639118f2017-06-19 15:48:02 -0700645 # Replace the AVB signing keys, if any.
646 ReplaceAvbSigningKeys(misc_info)
647
Tao Bao19b02fe2019-10-09 00:04:28 -0700648 # Rewrite the props in AVB signing args.
649 if misc_info.get('avb_enable') == 'true':
650 RewriteAvbProps(misc_info)
651
Tao Bao46a59992017-06-05 11:55:16 -0700652 # Write back misc_info with the latest values.
653 ReplaceMiscInfoTxt(input_tf_zip, output_tf_zip, misc_info)
654
Doug Zongker8e931bf2009-04-06 15:21:45 -0700655
Robert Craig817c5742013-04-19 10:59:22 -0400656def ReplaceCerts(data):
Tao Bao66472632017-12-04 17:16:36 -0800657 """Replaces all the occurences of X.509 certs with the new ones.
Robert Craig817c5742013-04-19 10:59:22 -0400658
Tao Bao66472632017-12-04 17:16:36 -0800659 The mapping info is read from OPTIONS.key_map. Non-existent certificate will
660 be skipped. After the replacement, it additionally checks for duplicate
661 entries, which would otherwise fail the policy loading code in
662 frameworks/base/services/core/java/com/android/server/pm/SELinuxMMAC.java.
663
664 Args:
665 data: Input string that contains a set of X.509 certs.
666
667 Returns:
668 A string after the replacement.
669
670 Raises:
671 AssertionError: On finding duplicate entries.
672 """
Tao Baoa3705452019-06-24 15:33:41 -0700673 for old, new in OPTIONS.key_map.items():
Tao Bao66472632017-12-04 17:16:36 -0800674 if OPTIONS.verbose:
675 print(" Replacing %s.x509.pem with %s.x509.pem" % (old, new))
676
677 try:
678 with open(old + ".x509.pem") as old_fp:
679 old_cert16 = base64.b16encode(
Tao Baoa3705452019-06-24 15:33:41 -0700680 common.ParseCertificate(old_fp.read())).decode().lower()
Tao Bao66472632017-12-04 17:16:36 -0800681 with open(new + ".x509.pem") as new_fp:
682 new_cert16 = base64.b16encode(
Tao Baoa3705452019-06-24 15:33:41 -0700683 common.ParseCertificate(new_fp.read())).decode().lower()
Tao Bao66472632017-12-04 17:16:36 -0800684 except IOError as e:
685 if OPTIONS.verbose or e.errno != errno.ENOENT:
686 print(" Error accessing %s: %s.\nSkip replacing %s.x509.pem with "
687 "%s.x509.pem." % (e.filename, e.strerror, old, new))
688 continue
689
690 # Only match entire certs.
691 pattern = "\\b" + old_cert16 + "\\b"
692 (data, num) = re.subn(pattern, new_cert16, data, flags=re.IGNORECASE)
693
694 if OPTIONS.verbose:
695 print(" Replaced %d occurence(s) of %s.x509.pem with %s.x509.pem" % (
696 num, old, new))
697
698 # Verify that there're no duplicate entries after the replacement. Note that
699 # it's only checking entries with global seinfo at the moment (i.e. ignoring
700 # the ones with inner packages). (Bug: 69479366)
701 root = ElementTree.fromstring(data)
702 signatures = [signer.attrib['signature'] for signer in root.findall('signer')]
703 assert len(signatures) == len(set(signatures)), \
704 "Found duplicate entries after cert replacement: {}".format(data)
Robert Craig817c5742013-04-19 10:59:22 -0400705
706 return data
707
708
Doug Zongkerc09abc82010-01-11 13:09:15 -0800709def EditTags(tags):
Tao Baoa7054ee2017-12-08 14:42:16 -0800710 """Applies the edits to the tag string as specified in OPTIONS.tag_changes.
711
712 Args:
713 tags: The input string that contains comma-separated tags.
714
715 Returns:
716 The updated tags (comma-separated and sorted).
717 """
Doug Zongkerc09abc82010-01-11 13:09:15 -0800718 tags = set(tags.split(","))
719 for ch in OPTIONS.tag_changes:
720 if ch[0] == "-":
721 tags.discard(ch[1:])
722 elif ch[0] == "+":
723 tags.add(ch[1:])
724 return ",".join(sorted(tags))
725
726
Tao Baoa7054ee2017-12-08 14:42:16 -0800727def RewriteProps(data):
728 """Rewrites the system properties in the given string.
729
730 Each property is expected in 'key=value' format. The properties that contain
731 build tags (i.e. test-keys, dev-keys) will be updated accordingly by calling
732 EditTags().
733
734 Args:
735 data: Input string, separated by newlines.
736
737 Returns:
738 The string with modified properties.
739 """
Doug Zongker17aa9442009-04-17 10:15:58 -0700740 output = []
741 for line in data.split("\n"):
742 line = line.strip()
743 original_line = line
Michael Rungedc2661a2014-06-03 14:43:11 -0700744 if line and line[0] != '#' and "=" in line:
Doug Zongker17aa9442009-04-17 10:15:58 -0700745 key, value = line.split("=", 1)
Magnus Strandh234f4b42019-05-01 23:09:30 +0200746 if (key.startswith("ro.") and
747 key.endswith((".build.fingerprint", ".build.thumbprint"))):
Doug Zongkerc09abc82010-01-11 13:09:15 -0800748 pieces = value.split("/")
749 pieces[-1] = EditTags(pieces[-1])
750 value = "/".join(pieces)
Tao Baocb7ff772015-09-11 15:27:56 -0700751 elif key == "ro.bootimage.build.fingerprint":
752 pieces = value.split("/")
753 pieces[-1] = EditTags(pieces[-1])
754 value = "/".join(pieces)
Doug Zongker17aa9442009-04-17 10:15:58 -0700755 elif key == "ro.build.description":
Doug Zongkerc09abc82010-01-11 13:09:15 -0800756 pieces = value.split(" ")
Doug Zongker17aa9442009-04-17 10:15:58 -0700757 assert len(pieces) == 5
Doug Zongkerc09abc82010-01-11 13:09:15 -0800758 pieces[-1] = EditTags(pieces[-1])
759 value = " ".join(pieces)
Magnus Strandh234f4b42019-05-01 23:09:30 +0200760 elif key.startswith("ro.") and key.endswith(".build.tags"):
Doug Zongkerc09abc82010-01-11 13:09:15 -0800761 value = EditTags(value)
Doug Zongkera8608a72013-07-23 11:51:04 -0700762 elif key == "ro.build.display.id":
763 # change, eg, "JWR66N dev-keys" to "JWR66N"
764 value = value.split()
Michael Rungedc2661a2014-06-03 14:43:11 -0700765 if len(value) > 1 and value[-1].endswith("-keys"):
Andrew Boie73d5abb2013-12-11 12:42:03 -0800766 value.pop()
767 value = " ".join(value)
Doug Zongkerc09abc82010-01-11 13:09:15 -0800768 line = key + "=" + value
Doug Zongker17aa9442009-04-17 10:15:58 -0700769 if line != original_line:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800770 print(" replace: ", original_line)
771 print(" with: ", line)
Doug Zongker17aa9442009-04-17 10:15:58 -0700772 output.append(line)
773 return "\n".join(output) + "\n"
774
775
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700776def WriteOtacerts(output_zip, filename, keys):
777 """Constructs a zipfile from given keys; and writes it to output_zip.
778
779 Args:
780 output_zip: The output target_files zip.
781 filename: The archive name in the output zip.
782 keys: A list of public keys to use during OTA package verification.
783 """
Tao Baobb733882019-07-24 23:31:19 -0700784 temp_file = io.BytesIO()
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700785 certs_zip = zipfile.ZipFile(temp_file, "w")
786 for k in keys:
787 common.ZipWrite(certs_zip, k)
788 common.ZipClose(certs_zip)
789 common.ZipWriteStr(output_zip, filename, temp_file.getvalue())
790
791
Doug Zongker831840e2011-09-22 10:28:04 -0700792def ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info):
Doug Zongker8e931bf2009-04-06 15:21:45 -0700793 try:
794 keylist = input_tf_zip.read("META/otakeys.txt").split()
795 except KeyError:
T.R. Fullharta28acc62013-03-18 10:31:26 -0700796 raise common.ExternalError("can't read META/otakeys.txt from input")
Doug Zongker8e931bf2009-04-06 15:21:45 -0700797
Tao Baof718f902017-11-09 10:10:10 -0800798 extra_recovery_keys = misc_info.get("extra_recovery_keys")
Doug Zongkere121d6a2011-02-01 14:13:52 -0800799 if extra_recovery_keys:
800 extra_recovery_keys = [OPTIONS.key_map.get(k, k) + ".x509.pem"
801 for k in extra_recovery_keys.split()]
802 if extra_recovery_keys:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800803 print("extra recovery-only key(s): " + ", ".join(extra_recovery_keys))
Doug Zongkere121d6a2011-02-01 14:13:52 -0800804 else:
805 extra_recovery_keys = []
806
Doug Zongker8e931bf2009-04-06 15:21:45 -0700807 mapped_keys = []
808 for k in keylist:
809 m = re.match(r"^(.*)\.x509\.pem$", k)
810 if not m:
Doug Zongker412c02f2014-02-13 10:58:24 -0800811 raise common.ExternalError(
812 "can't parse \"%s\" from META/otakeys.txt" % (k,))
Doug Zongker8e931bf2009-04-06 15:21:45 -0700813 k = m.group(1)
814 mapped_keys.append(OPTIONS.key_map.get(k, k) + ".x509.pem")
815
Doug Zongkere05628c2009-08-20 17:38:42 -0700816 if mapped_keys:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800817 print("using:\n ", "\n ".join(mapped_keys))
818 print("for OTA package verification")
Doug Zongkere05628c2009-08-20 17:38:42 -0700819 else:
Doug Zongker831840e2011-09-22 10:28:04 -0700820 devkey = misc_info.get("default_system_dev_certificate",
Dan Willemsen0ab1be62019-04-09 21:35:37 -0700821 "build/make/target/product/security/testkey")
Tao Baof718f902017-11-09 10:10:10 -0800822 mapped_devkey = OPTIONS.key_map.get(devkey, devkey)
823 if mapped_devkey != devkey:
824 misc_info["default_system_dev_certificate"] = mapped_devkey
825 mapped_keys.append(mapped_devkey + ".x509.pem")
Tao Baoa80ed222016-06-16 14:41:24 -0700826 print("META/otakeys.txt has no keys; using %s for OTA package"
827 " verification." % (mapped_keys[0],))
Doug Zongker8e931bf2009-04-06 15:21:45 -0700828
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700829 # recovery now uses the same x509.pem version of the keys.
Doug Zongkere121d6a2011-02-01 14:13:52 -0800830 # extra_recovery_keys are used only in recovery.
Tom Cherry2929cad2018-09-20 11:04:37 -0700831 if misc_info.get("recovery_as_boot") == "true":
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700832 recovery_keys_location = "BOOT/RAMDISK/system/etc/security/otacerts.zip"
Tao Baoa80ed222016-06-16 14:41:24 -0700833 else:
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700834 recovery_keys_location = "RECOVERY/RAMDISK/system/etc/security/otacerts.zip"
835
836 WriteOtacerts(output_tf_zip, recovery_keys_location,
837 mapped_keys + extra_recovery_keys)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700838
839 # SystemUpdateActivity uses the x509.pem version of the keys, but
840 # put into a zipfile system/etc/security/otacerts.zip.
Doug Zongkere121d6a2011-02-01 14:13:52 -0800841 # We DO NOT include the extra_recovery_keys (if any) here.
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700842 WriteOtacerts(output_tf_zip, "SYSTEM/etc/security/otacerts.zip", mapped_keys)
Doug Zongkereef39442009-04-02 12:14:19 -0700843
Tao Baoa80ed222016-06-16 14:41:24 -0700844
Tao Bao8adcfd12016-06-17 17:01:22 -0700845
Tao Bao0c28d2d2017-12-24 10:37:38 -0800846def ReplaceVerityPublicKey(output_zip, filename, key_path):
847 """Replaces the verity public key at the given path in the given zip.
848
849 Args:
850 output_zip: The output target_files zip.
851 filename: The archive name in the output zip.
852 key_path: The path to the public key.
853 """
854 print("Replacing verity public key with %s" % (key_path,))
855 common.ZipWrite(output_zip, key_path, arcname=filename)
Geremy Condraf19b3652014-07-29 17:54:54 -0700856
Tao Bao8adcfd12016-06-17 17:01:22 -0700857
Tao Bao46a59992017-06-05 11:55:16 -0700858def ReplaceVerityPrivateKey(misc_info, key_path):
Tao Bao0c28d2d2017-12-24 10:37:38 -0800859 """Replaces the verity private key in misc_info dict.
860
861 Args:
862 misc_info: The info dict.
863 key_path: The path to the private key in PKCS#8 format.
864 """
865 print("Replacing verity private key with %s" % (key_path,))
Andrew Boied083f0b2014-09-15 16:01:07 -0700866 misc_info["verity_key"] = key_path
Doug Zongkereef39442009-04-02 12:14:19 -0700867
Tao Bao8adcfd12016-06-17 17:01:22 -0700868
Tao Baoe838d142017-12-23 23:44:48 -0800869def ReplaceVerityKeyId(input_zip, output_zip, key_path):
870 """Replaces the veritykeyid parameter in BOOT/cmdline.
871
872 Args:
873 input_zip: The input target_files zip, which should be already open.
874 output_zip: The output target_files zip, which should be already open and
875 writable.
876 key_path: The path to the PEM encoded X.509 certificate.
877 """
Tao Baoa3705452019-06-24 15:33:41 -0700878 in_cmdline = input_zip.read("BOOT/cmdline").decode()
Tao Baoe838d142017-12-23 23:44:48 -0800879 # Copy in_cmdline to output_zip if veritykeyid is not present.
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700880 if "veritykeyid" not in in_cmdline:
Tao Baoe838d142017-12-23 23:44:48 -0800881 common.ZipWriteStr(output_zip, "BOOT/cmdline", in_cmdline)
882 return
883
Tao Bao0c28d2d2017-12-24 10:37:38 -0800884 out_buffer = []
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700885 for param in in_cmdline.split():
Tao Baoe838d142017-12-23 23:44:48 -0800886 if "veritykeyid" not in param:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800887 out_buffer.append(param)
Tao Baoe838d142017-12-23 23:44:48 -0800888 continue
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700889
Tao Baoe838d142017-12-23 23:44:48 -0800890 # Extract keyid using openssl command.
891 p = common.Run(["openssl", "x509", "-in", key_path, "-text"],
Tao Baode1d4792018-02-20 10:05:46 -0800892 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
Tao Baoe838d142017-12-23 23:44:48 -0800893 keyid, stderr = p.communicate()
894 assert p.returncode == 0, "Failed to dump certificate: {}".format(stderr)
895 keyid = re.search(
896 r'keyid:([0-9a-fA-F:]*)', keyid).group(1).replace(':', '').lower()
897 print("Replacing verity keyid with {}".format(keyid))
898 out_buffer.append("veritykeyid=id:%s" % (keyid,))
899
900 out_cmdline = ' '.join(out_buffer).strip() + '\n'
901 common.ZipWriteStr(output_zip, "BOOT/cmdline", out_cmdline)
Tao Bao46a59992017-06-05 11:55:16 -0700902
903
904def ReplaceMiscInfoTxt(input_zip, output_zip, misc_info):
905 """Replaces META/misc_info.txt.
906
907 Only writes back the ones in the original META/misc_info.txt. Because the
908 current in-memory dict contains additional items computed at runtime.
909 """
910 misc_info_old = common.LoadDictionaryFromLines(
Tao Baoa3705452019-06-24 15:33:41 -0700911 input_zip.read('META/misc_info.txt').decode().split('\n'))
Tao Bao46a59992017-06-05 11:55:16 -0700912 items = []
913 for key in sorted(misc_info):
914 if key in misc_info_old:
915 items.append('%s=%s' % (key, misc_info[key]))
916 common.ZipWriteStr(output_zip, "META/misc_info.txt", '\n'.join(items))
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700917
Tao Bao8adcfd12016-06-17 17:01:22 -0700918
Tao Bao639118f2017-06-19 15:48:02 -0700919def ReplaceAvbSigningKeys(misc_info):
920 """Replaces the AVB signing keys."""
921
Tao Bao639118f2017-06-19 15:48:02 -0700922 def ReplaceAvbPartitionSigningKey(partition):
923 key = OPTIONS.avb_keys.get(partition)
924 if not key:
925 return
926
927 algorithm = OPTIONS.avb_algorithms.get(partition)
928 assert algorithm, 'Missing AVB signing algorithm for %s' % (partition,)
929
Tao Bao0c28d2d2017-12-24 10:37:38 -0800930 print('Replacing AVB signing key for %s with "%s" (%s)' % (
931 partition, key, algorithm))
Tao Bao639118f2017-06-19 15:48:02 -0700932 misc_info['avb_' + partition + '_algorithm'] = algorithm
933 misc_info['avb_' + partition + '_key_path'] = key
934
935 extra_args = OPTIONS.avb_extra_args.get(partition)
936 if extra_args:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800937 print('Setting extra AVB signing args for %s to "%s"' % (
938 partition, extra_args))
Tao Bao639118f2017-06-19 15:48:02 -0700939 args_key = AVB_FOOTER_ARGS_BY_PARTITION[partition]
940 misc_info[args_key] = (misc_info.get(args_key, '') + ' ' + extra_args)
941
942 for partition in AVB_FOOTER_ARGS_BY_PARTITION:
943 ReplaceAvbPartitionSigningKey(partition)
944
945
Tao Bao19b02fe2019-10-09 00:04:28 -0700946def RewriteAvbProps(misc_info):
947 """Rewrites the props in AVB signing args."""
948 for partition, args_key in AVB_FOOTER_ARGS_BY_PARTITION.items():
949 args = misc_info.get(args_key)
950 if not args:
951 continue
952
953 tokens = []
954 changed = False
955 for token in args.split(' '):
956 fingerprint_key = 'com.android.build.{}.fingerprint'.format(partition)
957 if not token.startswith(fingerprint_key):
958 tokens.append(token)
959 continue
960 prefix, tag = token.rsplit('/', 1)
961 tokens.append('{}/{}'.format(prefix, EditTags(tag)))
962 changed = True
963
964 if changed:
965 result = ' '.join(tokens)
966 print('Rewriting AVB prop for {}:\n'.format(partition))
967 print(' replace: {}'.format(args))
968 print(' with: {}'.format(result))
969 misc_info[args_key] = result
970
971
Doug Zongker831840e2011-09-22 10:28:04 -0700972def BuildKeyMap(misc_info, key_mapping_options):
973 for s, d in key_mapping_options:
974 if s is None: # -d option
975 devkey = misc_info.get("default_system_dev_certificate",
Dan Willemsen0ab1be62019-04-09 21:35:37 -0700976 "build/make/target/product/security/testkey")
Doug Zongker831840e2011-09-22 10:28:04 -0700977 devkeydir = os.path.dirname(devkey)
978
979 OPTIONS.key_map.update({
980 devkeydir + "/testkey": d + "/releasekey",
981 devkeydir + "/devkey": d + "/releasekey",
982 devkeydir + "/media": d + "/media",
983 devkeydir + "/shared": d + "/shared",
984 devkeydir + "/platform": d + "/platform",
Oleh Cherpak982e6082019-12-10 12:58:54 +0200985 devkeydir + "/networkstack": d + "/networkstack",
Doug Zongker831840e2011-09-22 10:28:04 -0700986 })
987 else:
988 OPTIONS.key_map[s] = d
989
990
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800991def GetApiLevelAndCodename(input_tf_zip):
Tao Baoa3705452019-06-24 15:33:41 -0700992 data = input_tf_zip.read("SYSTEM/build.prop").decode()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800993 api_level = None
994 codename = None
995 for line in data.split("\n"):
996 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800997 if line and line[0] != '#' and "=" in line:
998 key, value = line.split("=", 1)
999 key = key.strip()
1000 if key == "ro.build.version.sdk":
1001 api_level = int(value.strip())
1002 elif key == "ro.build.version.codename":
1003 codename = value.strip()
1004
1005 if api_level is None:
1006 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
1007 if codename is None:
1008 raise ValueError("No ro.build.version.codename in SYSTEM/build.prop")
1009
1010 return (api_level, codename)
1011
1012
1013def GetCodenameToApiLevelMap(input_tf_zip):
Tao Baoa3705452019-06-24 15:33:41 -07001014 data = input_tf_zip.read("SYSTEM/build.prop").decode()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001015 api_level = None
1016 codenames = None
1017 for line in data.split("\n"):
1018 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001019 if line and line[0] != '#' and "=" in line:
1020 key, value = line.split("=", 1)
1021 key = key.strip()
1022 if key == "ro.build.version.sdk":
1023 api_level = int(value.strip())
1024 elif key == "ro.build.version.all_codenames":
1025 codenames = value.strip().split(",")
1026
1027 if api_level is None:
1028 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
1029 if codenames is None:
1030 raise ValueError("No ro.build.version.all_codenames in SYSTEM/build.prop")
1031
Tao Baoa3705452019-06-24 15:33:41 -07001032 result = {}
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001033 for codename in codenames:
1034 codename = codename.strip()
Tao Baobadceb22019-03-15 09:33:43 -07001035 if codename:
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001036 result[codename] = api_level
1037 return result
1038
1039
Tao Baoaa7e9932019-03-15 09:37:01 -07001040def ReadApexKeysInfo(tf_zip):
1041 """Parses the APEX keys info from a given target-files zip.
1042
1043 Given a target-files ZipFile, parses the META/apexkeys.txt entry and returns a
1044 dict that contains the mapping from APEX names (e.g. com.android.tzdata) to a
1045 tuple of (payload_key, container_key).
1046
1047 Args:
1048 tf_zip: The input target_files ZipFile (already open).
1049
1050 Returns:
1051 (payload_key, container_key): payload_key contains the path to the payload
1052 signing key; container_key contains the path to the container signing
1053 key.
1054 """
1055 keys = {}
Tao Baoa3705452019-06-24 15:33:41 -07001056 for line in tf_zip.read('META/apexkeys.txt').decode().split('\n'):
Tao Baoaa7e9932019-03-15 09:37:01 -07001057 line = line.strip()
1058 if not line:
1059 continue
1060 matches = re.match(
1061 r'^name="(?P<NAME>.*)"\s+'
1062 r'public_key="(?P<PAYLOAD_PUBLIC_KEY>.*)"\s+'
1063 r'private_key="(?P<PAYLOAD_PRIVATE_KEY>.*)"\s+'
1064 r'container_certificate="(?P<CONTAINER_CERT>.*)"\s+'
1065 r'container_private_key="(?P<CONTAINER_PRIVATE_KEY>.*)"$',
1066 line)
1067 if not matches:
1068 continue
1069
1070 name = matches.group('NAME')
Tao Baoaa7e9932019-03-15 09:37:01 -07001071 payload_private_key = matches.group("PAYLOAD_PRIVATE_KEY")
1072
1073 def CompareKeys(pubkey, pubkey_suffix, privkey, privkey_suffix):
1074 pubkey_suffix_len = len(pubkey_suffix)
1075 privkey_suffix_len = len(privkey_suffix)
1076 return (pubkey.endswith(pubkey_suffix) and
1077 privkey.endswith(privkey_suffix) and
1078 pubkey[:-pubkey_suffix_len] == privkey[:-privkey_suffix_len])
1079
Tao Bao6d9e3da2019-03-26 12:59:25 -07001080 # Sanity check on the container key names, as we'll carry them without the
1081 # extensions. This doesn't apply to payload keys though, which we will use
1082 # full names only.
Tao Baoaa7e9932019-03-15 09:37:01 -07001083 container_cert = matches.group("CONTAINER_CERT")
1084 container_private_key = matches.group("CONTAINER_PRIVATE_KEY")
Tao Baof454c3a2019-04-24 23:53:42 -07001085 if container_cert == 'PRESIGNED' and container_private_key == 'PRESIGNED':
1086 container_key = 'PRESIGNED'
1087 elif CompareKeys(
Tao Baoaa7e9932019-03-15 09:37:01 -07001088 container_cert, OPTIONS.public_key_suffix,
1089 container_private_key, OPTIONS.private_key_suffix):
Tao Baof454c3a2019-04-24 23:53:42 -07001090 container_key = container_cert[:-len(OPTIONS.public_key_suffix)]
1091 else:
Tao Baoaa7e9932019-03-15 09:37:01 -07001092 raise ValueError("Failed to parse container keys: \n{}".format(line))
1093
Tao Baof454c3a2019-04-24 23:53:42 -07001094 keys[name] = (payload_private_key, container_key)
Tao Baoaa7e9932019-03-15 09:37:01 -07001095
1096 return keys
1097
1098
Doug Zongkereef39442009-04-02 12:14:19 -07001099def main(argv):
1100
Doug Zongker831840e2011-09-22 10:28:04 -07001101 key_mapping_options = []
1102
Doug Zongkereef39442009-04-02 12:14:19 -07001103 def option_handler(o, a):
Doug Zongker05d3dea2009-06-22 11:32:31 -07001104 if o in ("-e", "--extra_apks"):
Doug Zongkereef39442009-04-02 12:14:19 -07001105 names, key = a.split("=")
1106 names = names.split(",")
1107 for n in names:
1108 OPTIONS.extra_apks[n] = key
Tao Baoaa7e9932019-03-15 09:37:01 -07001109 elif o == "--extra_apex_payload_key":
1110 apex_name, key = a.split("=")
1111 OPTIONS.extra_apex_payload_keys[apex_name] = key
Tao Bao93c2a012018-06-19 12:19:35 -07001112 elif o == "--skip_apks_with_path_prefix":
1113 # Sanity check the prefix, which must be in all upper case.
1114 prefix = a.split('/')[0]
1115 if not prefix or prefix != prefix.upper():
1116 raise ValueError("Invalid path prefix '%s'" % (a,))
1117 OPTIONS.skip_apks_with_path_prefix.add(a)
Doug Zongkereef39442009-04-02 12:14:19 -07001118 elif o in ("-d", "--default_key_mappings"):
Doug Zongker831840e2011-09-22 10:28:04 -07001119 key_mapping_options.append((None, a))
Doug Zongkereef39442009-04-02 12:14:19 -07001120 elif o in ("-k", "--key_mapping"):
Doug Zongker831840e2011-09-22 10:28:04 -07001121 key_mapping_options.append(a.split("=", 1))
Doug Zongker8e931bf2009-04-06 15:21:45 -07001122 elif o in ("-o", "--replace_ota_keys"):
1123 OPTIONS.replace_ota_keys = True
Doug Zongkerae877012009-04-21 10:04:51 -07001124 elif o in ("-t", "--tag_changes"):
1125 new = []
1126 for i in a.split(","):
1127 i = i.strip()
1128 if not i or i[0] not in "-+":
1129 raise ValueError("Bad tag change '%s'" % (i,))
1130 new.append(i[0] + i[1:].strip())
1131 OPTIONS.tag_changes = tuple(new)
Geremy Condraf19b3652014-07-29 17:54:54 -07001132 elif o == "--replace_verity_public_key":
1133 OPTIONS.replace_verity_public_key = (True, a)
1134 elif o == "--replace_verity_private_key":
1135 OPTIONS.replace_verity_private_key = (True, a)
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001136 elif o == "--replace_verity_keyid":
1137 OPTIONS.replace_verity_keyid = (True, a)
Tao Bao639118f2017-06-19 15:48:02 -07001138 elif o == "--avb_vbmeta_key":
1139 OPTIONS.avb_keys['vbmeta'] = a
1140 elif o == "--avb_vbmeta_algorithm":
1141 OPTIONS.avb_algorithms['vbmeta'] = a
1142 elif o == "--avb_vbmeta_extra_args":
1143 OPTIONS.avb_extra_args['vbmeta'] = a
1144 elif o == "--avb_boot_key":
1145 OPTIONS.avb_keys['boot'] = a
1146 elif o == "--avb_boot_algorithm":
1147 OPTIONS.avb_algorithms['boot'] = a
1148 elif o == "--avb_boot_extra_args":
1149 OPTIONS.avb_extra_args['boot'] = a
1150 elif o == "--avb_dtbo_key":
1151 OPTIONS.avb_keys['dtbo'] = a
1152 elif o == "--avb_dtbo_algorithm":
1153 OPTIONS.avb_algorithms['dtbo'] = a
1154 elif o == "--avb_dtbo_extra_args":
1155 OPTIONS.avb_extra_args['dtbo'] = a
1156 elif o == "--avb_system_key":
1157 OPTIONS.avb_keys['system'] = a
1158 elif o == "--avb_system_algorithm":
1159 OPTIONS.avb_algorithms['system'] = a
1160 elif o == "--avb_system_extra_args":
1161 OPTIONS.avb_extra_args['system'] = a
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001162 elif o == "--avb_system_other_key":
1163 OPTIONS.avb_keys['system_other'] = a
1164 elif o == "--avb_system_other_algorithm":
1165 OPTIONS.avb_algorithms['system_other'] = a
1166 elif o == "--avb_system_other_extra_args":
1167 OPTIONS.avb_extra_args['system_other'] = a
Tao Bao639118f2017-06-19 15:48:02 -07001168 elif o == "--avb_vendor_key":
1169 OPTIONS.avb_keys['vendor'] = a
1170 elif o == "--avb_vendor_algorithm":
1171 OPTIONS.avb_algorithms['vendor'] = a
1172 elif o == "--avb_vendor_extra_args":
1173 OPTIONS.avb_extra_args['vendor'] = a
Tao Baod6085d62019-05-06 12:55:42 -07001174 elif o == "--avb_vbmeta_system_key":
1175 OPTIONS.avb_keys['vbmeta_system'] = a
1176 elif o == "--avb_vbmeta_system_algorithm":
1177 OPTIONS.avb_algorithms['vbmeta_system'] = a
1178 elif o == "--avb_vbmeta_system_extra_args":
1179 OPTIONS.avb_extra_args['vbmeta_system'] = a
1180 elif o == "--avb_vbmeta_vendor_key":
1181 OPTIONS.avb_keys['vbmeta_vendor'] = a
1182 elif o == "--avb_vbmeta_vendor_algorithm":
1183 OPTIONS.avb_algorithms['vbmeta_vendor'] = a
1184 elif o == "--avb_vbmeta_vendor_extra_args":
1185 OPTIONS.avb_extra_args['vbmeta_vendor'] = a
Tao Baoaa7e9932019-03-15 09:37:01 -07001186 elif o == "--avb_apex_extra_args":
1187 OPTIONS.avb_extra_args['apex'] = a
Doug Zongkereef39442009-04-02 12:14:19 -07001188 else:
1189 return False
1190 return True
1191
Tao Bao639118f2017-06-19 15:48:02 -07001192 args = common.ParseOptions(
1193 argv, __doc__,
1194 extra_opts="e:d:k:ot:",
1195 extra_long_opts=[
Tao Bao0c28d2d2017-12-24 10:37:38 -08001196 "extra_apks=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001197 "extra_apex_payload_key=",
Tao Bao93c2a012018-06-19 12:19:35 -07001198 "skip_apks_with_path_prefix=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001199 "default_key_mappings=",
1200 "key_mapping=",
1201 "replace_ota_keys",
1202 "tag_changes=",
1203 "replace_verity_public_key=",
1204 "replace_verity_private_key=",
1205 "replace_verity_keyid=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001206 "avb_apex_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001207 "avb_vbmeta_algorithm=",
1208 "avb_vbmeta_key=",
1209 "avb_vbmeta_extra_args=",
1210 "avb_boot_algorithm=",
1211 "avb_boot_key=",
1212 "avb_boot_extra_args=",
1213 "avb_dtbo_algorithm=",
1214 "avb_dtbo_key=",
1215 "avb_dtbo_extra_args=",
1216 "avb_system_algorithm=",
1217 "avb_system_key=",
1218 "avb_system_extra_args=",
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001219 "avb_system_other_algorithm=",
1220 "avb_system_other_key=",
1221 "avb_system_other_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001222 "avb_vendor_algorithm=",
1223 "avb_vendor_key=",
1224 "avb_vendor_extra_args=",
Tao Baod6085d62019-05-06 12:55:42 -07001225 "avb_vbmeta_system_algorithm=",
1226 "avb_vbmeta_system_key=",
1227 "avb_vbmeta_system_extra_args=",
1228 "avb_vbmeta_vendor_algorithm=",
1229 "avb_vbmeta_vendor_key=",
1230 "avb_vbmeta_vendor_extra_args=",
Tao Bao639118f2017-06-19 15:48:02 -07001231 ],
1232 extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001233
1234 if len(args) != 2:
1235 common.Usage(__doc__)
1236 sys.exit(1)
1237
Tao Baobadceb22019-03-15 09:33:43 -07001238 common.InitLogging()
1239
Doug Zongkereef39442009-04-02 12:14:19 -07001240 input_zip = zipfile.ZipFile(args[0], "r")
Tao Bao2b8f4892017-06-13 12:54:58 -07001241 output_zip = zipfile.ZipFile(args[1], "w",
1242 compression=zipfile.ZIP_DEFLATED,
1243 allowZip64=True)
Doug Zongkereef39442009-04-02 12:14:19 -07001244
Doug Zongker831840e2011-09-22 10:28:04 -07001245 misc_info = common.LoadInfoDict(input_zip)
1246
1247 BuildKeyMap(misc_info, key_mapping_options)
1248
Tao Baoaa7e9932019-03-15 09:37:01 -07001249 apk_keys_info, compressed_extension = common.ReadApkCerts(input_zip)
1250 apk_keys = GetApkCerts(apk_keys_info)
Doug Zongkereb338ef2009-05-20 16:50:49 -07001251
Tao Baoaa7e9932019-03-15 09:37:01 -07001252 apex_keys_info = ReadApexKeysInfo(input_zip)
1253 apex_keys = GetApexKeys(apex_keys_info, apk_keys)
1254
Tianjie Xu88a759d2020-01-23 10:47:54 -08001255 # TODO(xunchang) check for the apks inside the apex files, and abort early if
1256 # the keys are not available.
Tao Baoaa7e9932019-03-15 09:37:01 -07001257 CheckApkAndApexKeysAvailable(
1258 input_zip,
1259 set(apk_keys.keys()) | set(apex_keys.keys()),
Tao Baoe1343992019-03-19 12:24:03 -07001260 compressed_extension,
1261 apex_keys)
Tao Baoaa7e9932019-03-15 09:37:01 -07001262
1263 key_passwords = common.GetKeyPasswords(
1264 set(apk_keys.values()) | set(itertools.chain(*apex_keys.values())))
Tao Bao9aa4b9b2016-09-29 17:53:56 -07001265 platform_api_level, _ = GetApiLevelAndCodename(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001266 codename_to_api_level_map = GetCodenameToApiLevelMap(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001267
Doug Zongker412c02f2014-02-13 10:58:24 -08001268 ProcessTargetFiles(input_zip, output_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -07001269 apk_keys, apex_keys, key_passwords,
1270 platform_api_level, codename_to_api_level_map,
Narayan Kamatha07bf042017-08-14 14:49:21 +01001271 compressed_extension)
Doug Zongker8e931bf2009-04-06 15:21:45 -07001272
Tao Bao2ed665a2015-04-01 11:21:55 -07001273 common.ZipClose(input_zip)
1274 common.ZipClose(output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001275
Tianjie Xub48589a2016-08-03 19:21:52 -07001276 # Skip building userdata.img and cache.img when signing the target files.
Tianjie Xu616fbeb2017-05-23 14:51:02 -07001277 new_args = ["--is_signing"]
1278 # add_img_to_target_files builds the system image from scratch, so the
1279 # recovery patch is guaranteed to be regenerated there.
1280 if OPTIONS.rebuild_recovery:
1281 new_args.append("--rebuild_recovery")
1282 new_args.append(args[1])
Tianjie Xub48589a2016-08-03 19:21:52 -07001283 add_img_to_target_files.main(new_args)
Doug Zongker3c84f562014-07-31 11:06:30 -07001284
Tao Bao0c28d2d2017-12-24 10:37:38 -08001285 print("done.")
Doug Zongkereef39442009-04-02 12:14:19 -07001286
1287
1288if __name__ == '__main__':
1289 try:
1290 main(sys.argv[1:])
Tao Bao0c28d2d2017-12-24 10:37:38 -08001291 except common.ExternalError as e:
1292 print("\n ERROR: %s\n" % (e,))
Doug Zongkereef39442009-04-02 12:14:19 -07001293 sys.exit(1)
Tao Bao639118f2017-06-19 15:48:02 -07001294 finally:
1295 common.Cleanup()