blob: 0ef698e70b991f4239e56509aec4e0ddd456e05b [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.
Doug Zongkereef39442009-04-02 12:14:19 -0700106"""
107
Tao Bao0c28d2d2017-12-24 10:37:38 -0800108from __future__ import print_function
Doug Zongkereef39442009-04-02 12:14:19 -0700109
Robert Craig817c5742013-04-19 10:59:22 -0400110import base64
Doug Zongker8e931bf2009-04-06 15:21:45 -0700111import copy
Robert Craig817c5742013-04-19 10:59:22 -0400112import errno
Narayan Kamatha07bf042017-08-14 14:49:21 +0100113import gzip
Tao Baobb733882019-07-24 23:31:19 -0700114import io
Tao Baoaa7e9932019-03-15 09:37:01 -0700115import itertools
Tao Baobadceb22019-03-15 09:33:43 -0700116import logging
Doug Zongkereef39442009-04-02 12:14:19 -0700117import os
118import re
Narayan Kamatha07bf042017-08-14 14:49:21 +0100119import shutil
Tao Bao9fdd00f2017-07-12 11:57:05 -0700120import stat
Doug Zongkereef39442009-04-02 12:14:19 -0700121import subprocess
Tao Bao0c28d2d2017-12-24 10:37:38 -0800122import sys
Doug Zongkereef39442009-04-02 12:14:19 -0700123import tempfile
124import zipfile
Tao Bao66472632017-12-04 17:16:36 -0800125from xml.etree import ElementTree
Doug Zongkereef39442009-04-02 12:14:19 -0700126
Doug Zongker3c84f562014-07-31 11:06:30 -0700127import add_img_to_target_files
Tao Baoaa7e9932019-03-15 09:37:01 -0700128import apex_utils
Doug Zongkereef39442009-04-02 12:14:19 -0700129import common
130
Tao Bao0c28d2d2017-12-24 10:37:38 -0800131
132if sys.hexversion < 0x02070000:
133 print("Python 2.7 or newer is required.", file=sys.stderr)
134 sys.exit(1)
135
136
Tao Baobadceb22019-03-15 09:33:43 -0700137logger = logging.getLogger(__name__)
138
Doug Zongkereef39442009-04-02 12:14:19 -0700139OPTIONS = common.OPTIONS
140
141OPTIONS.extra_apks = {}
Tao Baoaa7e9932019-03-15 09:37:01 -0700142OPTIONS.extra_apex_payload_keys = {}
Tao Bao93c2a012018-06-19 12:19:35 -0700143OPTIONS.skip_apks_with_path_prefix = set()
Doug Zongkereef39442009-04-02 12:14:19 -0700144OPTIONS.key_map = {}
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700145OPTIONS.rebuild_recovery = False
Doug Zongker8e931bf2009-04-06 15:21:45 -0700146OPTIONS.replace_ota_keys = False
Geremy Condraf19b3652014-07-29 17:54:54 -0700147OPTIONS.replace_verity_public_key = False
148OPTIONS.replace_verity_private_key = False
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700149OPTIONS.replace_verity_keyid = False
Doug Zongker831840e2011-09-22 10:28:04 -0700150OPTIONS.tag_changes = ("-test-keys", "-dev-keys", "+release-keys")
Tao Bao639118f2017-06-19 15:48:02 -0700151OPTIONS.avb_keys = {}
152OPTIONS.avb_algorithms = {}
153OPTIONS.avb_extra_args = {}
Doug Zongkereef39442009-04-02 12:14:19 -0700154
Tao Bao0c28d2d2017-12-24 10:37:38 -0800155
Tao Bao19b02fe2019-10-09 00:04:28 -0700156AVB_FOOTER_ARGS_BY_PARTITION = {
157 'boot' : 'avb_boot_add_hash_footer_args',
158 'dtbo' : 'avb_dtbo_add_hash_footer_args',
159 'recovery' : 'avb_recovery_add_hash_footer_args',
160 'system' : 'avb_system_add_hashtree_footer_args',
161 'system_other' : 'avb_system_other_add_hashtree_footer_args',
162 'vendor' : 'avb_vendor_add_hashtree_footer_args',
163 'vendor_boot' : 'avb_vendor_boot_add_hash_footer_args',
164 'vbmeta' : 'avb_vbmeta_args',
165 'vbmeta_system' : 'avb_vbmeta_system_args',
166 'vbmeta_vendor' : 'avb_vbmeta_vendor_args',
167}
168
169
Narayan Kamatha07bf042017-08-14 14:49:21 +0100170def GetApkCerts(certmap):
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800171 # apply the key remapping to the contents of the file
Tao Baoa3705452019-06-24 15:33:41 -0700172 for apk, cert in certmap.items():
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800173 certmap[apk] = OPTIONS.key_map.get(cert, cert)
174
175 # apply all the -e options, overriding anything in the file
Tao Baoa3705452019-06-24 15:33:41 -0700176 for apk, cert in OPTIONS.extra_apks.items():
Doug Zongkerdecf9952009-12-15 17:27:49 -0800177 if not cert:
178 cert = "PRESIGNED"
Doug Zongkerad88c7c2009-04-14 12:34:27 -0700179 certmap[apk] = OPTIONS.key_map.get(cert, cert)
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800180
Doug Zongkereef39442009-04-02 12:14:19 -0700181 return certmap
182
183
Tao Baoaa7e9932019-03-15 09:37:01 -0700184def GetApexKeys(keys_info, key_map):
185 """Gets APEX payload and container signing keys by applying the mapping rules.
186
Tao Baoe1343992019-03-19 12:24:03 -0700187 Presigned payload / container keys will be set accordingly.
Tao Baoaa7e9932019-03-15 09:37:01 -0700188
189 Args:
190 keys_info: A dict that maps from APEX filenames to a tuple of (payload_key,
191 container_key).
192 key_map: A dict that overrides the keys, specified via command-line input.
193
194 Returns:
195 A dict that contains the updated APEX key mapping, which should be used for
196 the current signing.
Tao Baof98fa102019-04-24 14:51:25 -0700197
198 Raises:
199 AssertionError: On invalid container / payload key overrides.
Tao Baoaa7e9932019-03-15 09:37:01 -0700200 """
201 # Apply all the --extra_apex_payload_key options to override the payload
202 # signing keys in the given keys_info.
203 for apex, key in OPTIONS.extra_apex_payload_keys.items():
Tao Baoe1343992019-03-19 12:24:03 -0700204 if not key:
205 key = 'PRESIGNED'
Tao Bao34223092019-07-11 11:52:52 -0700206 if apex not in keys_info:
207 logger.warning('Failed to find %s in target_files; Ignored', apex)
208 continue
Tao Baoaa7e9932019-03-15 09:37:01 -0700209 keys_info[apex] = (key, keys_info[apex][1])
210
211 # Apply the key remapping to container keys.
212 for apex, (payload_key, container_key) in keys_info.items():
213 keys_info[apex] = (payload_key, key_map.get(container_key, container_key))
214
215 # Apply all the --extra_apks options to override the container keys.
216 for apex, key in OPTIONS.extra_apks.items():
217 # Skip non-APEX containers.
218 if apex not in keys_info:
219 continue
Tao Baoe1343992019-03-19 12:24:03 -0700220 if not key:
221 key = 'PRESIGNED'
Tao Baofa9de0a2019-03-18 10:24:17 -0700222 keys_info[apex] = (keys_info[apex][0], key_map.get(key, key))
Tao Baoaa7e9932019-03-15 09:37:01 -0700223
Tao Baof98fa102019-04-24 14:51:25 -0700224 # A PRESIGNED container entails a PRESIGNED payload. Apply this to all the
225 # APEX key pairs. However, a PRESIGNED container with non-PRESIGNED payload
226 # (overridden via commandline) indicates a config error, which should not be
227 # allowed.
228 for apex, (payload_key, container_key) in keys_info.items():
229 if container_key != 'PRESIGNED':
230 continue
231 if apex in OPTIONS.extra_apex_payload_keys:
232 payload_override = OPTIONS.extra_apex_payload_keys[apex]
233 assert payload_override == '', \
234 ("Invalid APEX key overrides: {} has PRESIGNED container but "
235 "non-PRESIGNED payload key {}").format(apex, payload_override)
236 if payload_key != 'PRESIGNED':
237 print(
238 "Setting {} payload as PRESIGNED due to PRESIGNED container".format(
239 apex))
240 keys_info[apex] = ('PRESIGNED', 'PRESIGNED')
241
Tao Baoaa7e9932019-03-15 09:37:01 -0700242 return keys_info
243
244
Tao Bao93c2a012018-06-19 12:19:35 -0700245def GetApkFileInfo(filename, compressed_extension, skipped_prefixes):
Tao Bao11f955c2018-06-19 12:19:35 -0700246 """Returns the APK info based on the given filename.
247
248 Checks if the given filename (with path) looks like an APK file, by taking the
Tao Bao93c2a012018-06-19 12:19:35 -0700249 compressed extension into consideration. If it appears to be an APK file,
250 further checks if the APK file should be skipped when signing, based on the
251 given path prefixes.
Tao Bao11f955c2018-06-19 12:19:35 -0700252
253 Args:
254 filename: Path to the file.
255 compressed_extension: The extension string of compressed APKs (e.g. ".gz"),
256 or None if there's no compressed APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700257 skipped_prefixes: A set/list/tuple of the path prefixes to be skipped.
Tao Bao11f955c2018-06-19 12:19:35 -0700258
259 Returns:
Tao Bao93c2a012018-06-19 12:19:35 -0700260 (is_apk, is_compressed, should_be_skipped): is_apk indicates whether the
261 given filename is an APK file. is_compressed indicates whether the APK file
262 is compressed (only meaningful when is_apk is True). should_be_skipped
263 indicates whether the filename matches any of the given prefixes to be
264 skipped.
Tao Bao11f955c2018-06-19 12:19:35 -0700265
266 Raises:
Tao Bao93c2a012018-06-19 12:19:35 -0700267 AssertionError: On invalid compressed_extension or skipped_prefixes inputs.
Tao Bao11f955c2018-06-19 12:19:35 -0700268 """
269 assert compressed_extension is None or compressed_extension.startswith('.'), \
270 "Invalid compressed_extension arg: '{}'".format(compressed_extension)
271
Tao Bao93c2a012018-06-19 12:19:35 -0700272 # skipped_prefixes should be one of set/list/tuple types. Other types such as
273 # str shouldn't be accepted.
Tao Baobadceb22019-03-15 09:33:43 -0700274 assert isinstance(skipped_prefixes, (set, list, tuple)), \
275 "Invalid skipped_prefixes input type: {}".format(type(skipped_prefixes))
Tao Bao93c2a012018-06-19 12:19:35 -0700276
Tao Bao11f955c2018-06-19 12:19:35 -0700277 compressed_apk_extension = (
278 ".apk" + compressed_extension if compressed_extension else None)
279 is_apk = (filename.endswith(".apk") or
280 (compressed_apk_extension and
281 filename.endswith(compressed_apk_extension)))
282 if not is_apk:
Tao Bao93c2a012018-06-19 12:19:35 -0700283 return (False, False, False)
Tao Bao11f955c2018-06-19 12:19:35 -0700284
285 is_compressed = (compressed_apk_extension and
286 filename.endswith(compressed_apk_extension))
Tao Bao93c2a012018-06-19 12:19:35 -0700287 should_be_skipped = filename.startswith(tuple(skipped_prefixes))
288 return (True, is_compressed, should_be_skipped)
Tao Bao11f955c2018-06-19 12:19:35 -0700289
290
Tao Baoaa7e9932019-03-15 09:37:01 -0700291def CheckApkAndApexKeysAvailable(input_tf_zip, known_keys,
Tao Baoe1343992019-03-19 12:24:03 -0700292 compressed_extension, apex_keys):
Tao Baoaa7e9932019-03-15 09:37:01 -0700293 """Checks that all the APKs and APEXes have keys specified.
Tao Bao11f955c2018-06-19 12:19:35 -0700294
295 Args:
296 input_tf_zip: An open target_files zip file.
Tao Baoaa7e9932019-03-15 09:37:01 -0700297 known_keys: A set of APKs and APEXes that have known signing keys.
Tao Bao11f955c2018-06-19 12:19:35 -0700298 compressed_extension: The extension string of compressed APKs, such as
Tao Baoaa7e9932019-03-15 09:37:01 -0700299 '.gz', or None if there's no compressed APKs.
Tao Baoe1343992019-03-19 12:24:03 -0700300 apex_keys: A dict that contains the key mapping from APEX name to
301 (payload_key, container_key).
Tao Bao11f955c2018-06-19 12:19:35 -0700302
303 Raises:
Tao Baoaa7e9932019-03-15 09:37:01 -0700304 AssertionError: On finding unknown APKs and APEXes.
Tao Bao11f955c2018-06-19 12:19:35 -0700305 """
Tao Baoaa7e9932019-03-15 09:37:01 -0700306 unknown_files = []
Doug Zongkereb338ef2009-05-20 16:50:49 -0700307 for info in input_tf_zip.infolist():
Tao Baoaa7e9932019-03-15 09:37:01 -0700308 # Handle APEXes first, e.g. SYSTEM/apex/com.android.tzdata.apex.
309 if (info.filename.startswith('SYSTEM/apex') and
310 info.filename.endswith('.apex')):
311 name = os.path.basename(info.filename)
312 if name not in known_keys:
313 unknown_files.append(name)
314 continue
315
316 # And APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700317 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
318 info.filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
319 if not is_apk or should_be_skipped:
Tao Bao11f955c2018-06-19 12:19:35 -0700320 continue
Tao Baoaa7e9932019-03-15 09:37:01 -0700321
Tao Bao11f955c2018-06-19 12:19:35 -0700322 name = os.path.basename(info.filename)
323 if is_compressed:
324 name = name[:-len(compressed_extension)]
Tao Baoaa7e9932019-03-15 09:37:01 -0700325 if name not in known_keys:
326 unknown_files.append(name)
Tao Bao11f955c2018-06-19 12:19:35 -0700327
Tao Baoaa7e9932019-03-15 09:37:01 -0700328 assert not unknown_files, \
Tao Bao11f955c2018-06-19 12:19:35 -0700329 ("No key specified for:\n {}\n"
330 "Use '-e <apkname>=' to specify a key (which may be an empty string to "
Tao Baoaa7e9932019-03-15 09:37:01 -0700331 "not sign this apk).".format("\n ".join(unknown_files)))
Doug Zongkereb338ef2009-05-20 16:50:49 -0700332
Tao Baoe1343992019-03-19 12:24:03 -0700333 # For all the APEXes, double check that we won't have an APEX that has only
Tao Baof98fa102019-04-24 14:51:25 -0700334 # one of the payload / container keys set. Note that non-PRESIGNED container
335 # with PRESIGNED payload could be allowed but currently unsupported. It would
336 # require changing SignApex implementation.
Tao Baoe1343992019-03-19 12:24:03 -0700337 if not apex_keys:
338 return
339
340 invalid_apexes = []
341 for info in input_tf_zip.infolist():
342 if (not info.filename.startswith('SYSTEM/apex') or
343 not info.filename.endswith('.apex')):
344 continue
345
346 name = os.path.basename(info.filename)
347 (payload_key, container_key) = apex_keys[name]
348 if ((payload_key in common.SPECIAL_CERT_STRINGS and
349 container_key not in common.SPECIAL_CERT_STRINGS) or
350 (payload_key not in common.SPECIAL_CERT_STRINGS and
351 container_key in common.SPECIAL_CERT_STRINGS)):
352 invalid_apexes.append(
353 "{}: payload_key {}, container_key {}".format(
354 name, payload_key, container_key))
355
356 assert not invalid_apexes, \
357 "Invalid APEX keys specified:\n {}\n".format(
358 "\n ".join(invalid_apexes))
359
Doug Zongkereb338ef2009-05-20 16:50:49 -0700360
Narayan Kamatha07bf042017-08-14 14:49:21 +0100361def SignApk(data, keyname, pw, platform_api_level, codename_to_api_level_map,
362 is_compressed):
Doug Zongkereef39442009-04-02 12:14:19 -0700363 unsigned = tempfile.NamedTemporaryFile()
364 unsigned.write(data)
365 unsigned.flush()
366
Narayan Kamatha07bf042017-08-14 14:49:21 +0100367 if is_compressed:
368 uncompressed = tempfile.NamedTemporaryFile()
Tao Bao0c28d2d2017-12-24 10:37:38 -0800369 with gzip.open(unsigned.name, "rb") as in_file, \
370 open(uncompressed.name, "wb") as out_file:
Narayan Kamatha07bf042017-08-14 14:49:21 +0100371 shutil.copyfileobj(in_file, out_file)
372
373 # Finally, close the "unsigned" file (which is gzip compressed), and then
374 # replace it with the uncompressed version.
375 #
376 # TODO(narayan): All this nastiness can be avoided if python 3.2 is in use,
377 # we could just gzip / gunzip in-memory buffers instead.
378 unsigned.close()
379 unsigned = uncompressed
380
Doug Zongkereef39442009-04-02 12:14:19 -0700381 signed = tempfile.NamedTemporaryFile()
382
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800383 # For pre-N builds, don't upgrade to SHA-256 JAR signatures based on the APK's
384 # minSdkVersion to avoid increasing incremental OTA update sizes. If an APK
385 # didn't change, we don't want its signature to change due to the switch
386 # from SHA-1 to SHA-256.
387 # By default, APK signer chooses SHA-256 signatures if the APK's minSdkVersion
388 # is 18 or higher. For pre-N builds we disable this mechanism by pretending
389 # that the APK's minSdkVersion is 1.
390 # For N+ builds, we let APK signer rely on the APK's minSdkVersion to
391 # determine whether to use SHA-256.
392 min_api_level = None
393 if platform_api_level > 23:
394 # Let APK signer choose whether to use SHA-1 or SHA-256, based on the APK's
395 # minSdkVersion attribute
396 min_api_level = None
397 else:
398 # Force APK signer to use SHA-1
399 min_api_level = 1
400
401 common.SignFile(unsigned.name, signed.name, keyname, pw,
Tao Bao0c28d2d2017-12-24 10:37:38 -0800402 min_api_level=min_api_level,
403 codename_to_api_level_map=codename_to_api_level_map)
Doug Zongkereef39442009-04-02 12:14:19 -0700404
Tao Bao0c28d2d2017-12-24 10:37:38 -0800405 data = None
Narayan Kamatha07bf042017-08-14 14:49:21 +0100406 if is_compressed:
407 # Recompress the file after it has been signed.
408 compressed = tempfile.NamedTemporaryFile()
Tao Bao0c28d2d2017-12-24 10:37:38 -0800409 with open(signed.name, "rb") as in_file, \
410 gzip.open(compressed.name, "wb") as out_file:
Narayan Kamatha07bf042017-08-14 14:49:21 +0100411 shutil.copyfileobj(in_file, out_file)
412
413 data = compressed.read()
414 compressed.close()
415 else:
416 data = signed.read()
417
Doug Zongkereef39442009-04-02 12:14:19 -0700418 unsigned.close()
419 signed.close()
420
421 return data
422
423
Doug Zongker412c02f2014-02-13 10:58:24 -0800424def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -0700425 apk_keys, apex_keys, key_passwords,
426 platform_api_level, codename_to_api_level_map,
Narayan Kamatha07bf042017-08-14 14:49:21 +0100427 compressed_extension):
Tao Bao93c2a012018-06-19 12:19:35 -0700428 # maxsize measures the maximum filename length, including the ones to be
429 # skipped.
Tao Bao0c28d2d2017-12-24 10:37:38 -0800430 maxsize = max(
431 [len(os.path.basename(i.filename)) for i in input_tf_zip.infolist()
Tao Bao93c2a012018-06-19 12:19:35 -0700432 if GetApkFileInfo(i.filename, compressed_extension, [])[0]])
Tao Baoa80ed222016-06-16 14:41:24 -0700433 system_root_image = misc_info.get("system_root_image") == "true"
Doug Zongker412c02f2014-02-13 10:58:24 -0800434
Doug Zongkereef39442009-04-02 12:14:19 -0700435 for info in input_tf_zip.infolist():
Tao Bao11f955c2018-06-19 12:19:35 -0700436 filename = info.filename
437 if filename.startswith("IMAGES/"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700438 continue
Doug Zongker3c84f562014-07-31 11:06:30 -0700439
Tao Bao04808502019-07-25 23:11:41 -0700440 # Skip OTA-specific images (e.g. split super images), which will be
441 # re-generated during signing.
Tao Bao33bf2682019-01-11 12:37:35 -0800442 if filename.startswith("OTA/") and filename.endswith(".img"):
443 continue
444
Tao Bao11f955c2018-06-19 12:19:35 -0700445 data = input_tf_zip.read(filename)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700446 out_info = copy.copy(info)
Tao Bao93c2a012018-06-19 12:19:35 -0700447 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
448 filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
449
450 if is_apk and should_be_skipped:
451 # Copy skipped APKs verbatim.
452 print(
453 "NOT signing: %s\n"
454 " (skipped due to matching prefix)" % (filename,))
455 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker412c02f2014-02-13 10:58:24 -0800456
Tao Baof2cffbd2015-07-22 12:33:18 -0700457 # Sign APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700458 elif is_apk:
Tao Bao11f955c2018-06-19 12:19:35 -0700459 name = os.path.basename(filename)
Narayan Kamatha07bf042017-08-14 14:49:21 +0100460 if is_compressed:
461 name = name[:-len(compressed_extension)]
462
Tao Baoaa7e9932019-03-15 09:37:01 -0700463 key = apk_keys[name]
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800464 if key not in common.SPECIAL_CERT_STRINGS:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800465 print(" signing: %-*s (%s)" % (maxsize, name, key))
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800466 signed_data = SignApk(data, key, key_passwords[key], platform_api_level,
Tao Bao0c28d2d2017-12-24 10:37:38 -0800467 codename_to_api_level_map, is_compressed)
Tao Bao2ed665a2015-04-01 11:21:55 -0700468 common.ZipWriteStr(output_tf_zip, out_info, signed_data)
Doug Zongkereef39442009-04-02 12:14:19 -0700469 else:
470 # an APK we're not supposed to sign.
Tao Bao93c2a012018-06-19 12:19:35 -0700471 print(
472 "NOT signing: %s\n"
473 " (skipped due to special cert string)" % (name,))
Tao Bao2ed665a2015-04-01 11:21:55 -0700474 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoa80ed222016-06-16 14:41:24 -0700475
Tao Baoaa7e9932019-03-15 09:37:01 -0700476 # Sign bundled APEX files.
477 elif filename.startswith("SYSTEM/apex") and filename.endswith(".apex"):
478 name = os.path.basename(filename)
479 payload_key, container_key = apex_keys[name]
480
Tao Baoe1343992019-03-19 12:24:03 -0700481 # We've asserted not having a case with only one of them PRESIGNED.
482 if (payload_key not in common.SPECIAL_CERT_STRINGS and
483 container_key not in common.SPECIAL_CERT_STRINGS):
484 print(" signing: %-*s container (%s)" % (
485 maxsize, name, container_key))
486 print(" : %-*s payload (%s)" % (
487 maxsize, name, payload_key))
Tao Baoaa7e9932019-03-15 09:37:01 -0700488
Tao Baoe7354ba2019-05-09 16:54:15 -0700489 signed_apex = apex_utils.SignApex(
Tao Bao1ac886e2019-06-26 11:58:22 -0700490 misc_info['avb_avbtool'],
Tao Baoe1343992019-03-19 12:24:03 -0700491 data,
492 payload_key,
493 container_key,
494 key_passwords[container_key],
495 codename_to_api_level_map,
Tao Bao448004a2019-09-19 07:55:02 -0700496 no_hashtree=True,
497 signing_args=OPTIONS.avb_extra_args.get('apex'))
Tao Baoe1343992019-03-19 12:24:03 -0700498 common.ZipWrite(output_tf_zip, signed_apex, filename)
Tao Baoaa7e9932019-03-15 09:37:01 -0700499
Tao Baoe1343992019-03-19 12:24:03 -0700500 else:
501 print(
502 "NOT signing: %s\n"
503 " (skipped due to special cert string)" % (name,))
504 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoaa7e9932019-03-15 09:37:01 -0700505
506 # AVB public keys for the installed APEXes, which will be updated later.
507 elif (os.path.dirname(filename) == 'SYSTEM/etc/security/apex' and
508 filename != 'SYSTEM/etc/security/apex/'):
509 continue
510
Tao Baoa80ed222016-06-16 14:41:24 -0700511 # System properties.
Tao Bao338c1b72019-06-21 09:38:24 -0700512 elif filename in (
513 "SYSTEM/build.prop",
514
515 "VENDOR/build.prop",
516 "SYSTEM/vendor/build.prop",
517
518 "ODM/etc/build.prop",
519 "VENDOR/odm/etc/build.prop",
520
521 "PRODUCT/build.prop",
522 "SYSTEM/product/build.prop",
523
Justin Yun6151e3f2019-06-25 15:58:13 +0900524 "SYSTEM_EXT/build.prop",
525 "SYSTEM/system_ext/build.prop",
Tao Bao338c1b72019-06-21 09:38:24 -0700526
527 "SYSTEM/etc/prop.default",
528 "BOOT/RAMDISK/prop.default",
529 "RECOVERY/RAMDISK/prop.default",
530
531 # ROOT/default.prop is a legacy path, but may still exist for upgrading
532 # devices that don't support `property_overrides_split_enabled`.
533 "ROOT/default.prop",
534
535 # RECOVERY/RAMDISK/default.prop is a legacy path, but will always exist
536 # as a symlink in the current code. So it's a no-op here. Keeping the
537 # path here for clarity.
538 "RECOVERY/RAMDISK/default.prop"):
Tao Bao11f955c2018-06-19 12:19:35 -0700539 print("Rewriting %s:" % (filename,))
Hung-ying Tyan7eb6a922017-05-01 21:56:26 +0800540 if stat.S_ISLNK(info.external_attr >> 16):
541 new_data = data
542 else:
Tao Baoa3705452019-06-24 15:33:41 -0700543 new_data = RewriteProps(data.decode())
Tao Bao2ed665a2015-04-01 11:21:55 -0700544 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700545
Tao Bao66472632017-12-04 17:16:36 -0800546 # Replace the certs in *mac_permissions.xml (there could be multiple, such
547 # as {system,vendor}/etc/selinux/{plat,nonplat}_mac_permissions.xml).
Tao Bao11f955c2018-06-19 12:19:35 -0700548 elif filename.endswith("mac_permissions.xml"):
549 print("Rewriting %s with new keys." % (filename,))
Tao Baoa3705452019-06-24 15:33:41 -0700550 new_data = ReplaceCerts(data.decode())
Tao Bao2ed665a2015-04-01 11:21:55 -0700551 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700552
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700553 # Ask add_img_to_target_files to rebuild the recovery patch if needed.
Tao Bao11f955c2018-06-19 12:19:35 -0700554 elif filename in ("SYSTEM/recovery-from-boot.p",
555 "SYSTEM/etc/recovery.img",
556 "SYSTEM/bin/install-recovery.sh"):
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700557 OPTIONS.rebuild_recovery = True
Tao Baoa80ed222016-06-16 14:41:24 -0700558
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700559 # Don't copy OTA certs if we're replacing them.
Tao Bao696bb332018-08-17 16:27:01 -0700560 elif (
561 OPTIONS.replace_ota_keys and
562 filename in (
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700563 "BOOT/RAMDISK/system/etc/security/otacerts.zip",
Tao Bao696bb332018-08-17 16:27:01 -0700564 "BOOT/RAMDISK/system/etc/update_engine/update-payload-key.pub.pem",
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700565 "RECOVERY/RAMDISK/system/etc/security/otacerts.zip",
Tao Bao696bb332018-08-17 16:27:01 -0700566 "SYSTEM/etc/security/otacerts.zip",
567 "SYSTEM/etc/update_engine/update-payload-key.pub.pem")):
Doug Zongker412c02f2014-02-13 10:58:24 -0800568 pass
Tao Baoa80ed222016-06-16 14:41:24 -0700569
Tao Bao46a59992017-06-05 11:55:16 -0700570 # Skip META/misc_info.txt since we will write back the new values later.
Tao Bao11f955c2018-06-19 12:19:35 -0700571 elif filename == "META/misc_info.txt":
Geremy Condraf19b3652014-07-29 17:54:54 -0700572 pass
Tao Bao8adcfd12016-06-17 17:01:22 -0700573
574 # Skip verity public key if we will replace it.
Michael Runge947894f2014-10-14 20:58:38 -0700575 elif (OPTIONS.replace_verity_public_key and
Tao Bao11f955c2018-06-19 12:19:35 -0700576 filename in ("BOOT/RAMDISK/verity_key",
577 "ROOT/verity_key")):
Geremy Condraf19b3652014-07-29 17:54:54 -0700578 pass
Tao Baoa80ed222016-06-16 14:41:24 -0700579
Tao Bao8adcfd12016-06-17 17:01:22 -0700580 # Skip verity keyid (for system_root_image use) if we will replace it.
Tao Bao11f955c2018-06-19 12:19:35 -0700581 elif OPTIONS.replace_verity_keyid and filename == "BOOT/cmdline":
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700582 pass
583
Tianjie Xu4f099002016-08-11 18:04:27 -0700584 # Skip the care_map as we will regenerate the system/vendor images.
Tianjie Xu4c05f4a2018-09-14 16:24:41 -0700585 elif filename == "META/care_map.pb" or filename == "META/care_map.txt":
Tianjie Xu4f099002016-08-11 18:04:27 -0700586 pass
587
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800588 # Updates system_other.avbpubkey in /product/etc/.
589 elif filename in (
590 "PRODUCT/etc/security/avb/system_other.avbpubkey",
591 "SYSTEM/product/etc/security/avb/system_other.avbpubkey"):
592 # Only update system_other's public key, if the corresponding signing
593 # key is specified via --avb_system_other_key.
594 signing_key = OPTIONS.avb_keys.get("system_other")
595 if signing_key:
Tao Bao1ac886e2019-06-26 11:58:22 -0700596 public_key = common.ExtractAvbPublicKey(
597 misc_info['avb_avbtool'], signing_key)
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800598 print(" Rewriting AVB public key of system_other in /product")
599 common.ZipWrite(output_tf_zip, public_key, filename)
600
Bowgo Tsai78369eb2019-04-23 12:28:44 +0800601 # Should NOT sign boot-debug.img.
602 elif filename in (
603 "BOOT/RAMDISK/force_debuggable",
604 "RECOVERY/RAMDISK/force_debuggable"
605 "RECOVERY/RAMDISK/first_stage_ramdisk/force_debuggable"):
606 raise common.ExternalError("debuggable boot.img cannot be signed")
607
Tao Baoa80ed222016-06-16 14:41:24 -0700608 # A non-APK file; copy it verbatim.
Doug Zongkereef39442009-04-02 12:14:19 -0700609 else:
Tao Bao2ed665a2015-04-01 11:21:55 -0700610 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700611
Doug Zongker412c02f2014-02-13 10:58:24 -0800612 if OPTIONS.replace_ota_keys:
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700613 ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info)
Doug Zongker412c02f2014-02-13 10:58:24 -0800614
Tao Bao46a59992017-06-05 11:55:16 -0700615 # Replace the keyid string in misc_info dict.
Tao Bao8adcfd12016-06-17 17:01:22 -0700616 if OPTIONS.replace_verity_private_key:
Tao Bao46a59992017-06-05 11:55:16 -0700617 ReplaceVerityPrivateKey(misc_info, OPTIONS.replace_verity_private_key[1])
Tao Bao8adcfd12016-06-17 17:01:22 -0700618
619 if OPTIONS.replace_verity_public_key:
Tao Baoc9981932019-09-16 12:10:43 -0700620 # Replace the one in root dir in system.img.
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700621 ReplaceVerityPublicKey(
Tao Baoc9981932019-09-16 12:10:43 -0700622 output_tf_zip, 'ROOT/verity_key', OPTIONS.replace_verity_public_key[1])
623
624 if not system_root_image:
625 # Additionally replace the copy in ramdisk if not using system-as-root.
626 ReplaceVerityPublicKey(
627 output_tf_zip,
628 'BOOT/RAMDISK/verity_key',
629 OPTIONS.replace_verity_public_key[1])
Tao Bao8adcfd12016-06-17 17:01:22 -0700630
631 # Replace the keyid string in BOOT/cmdline.
632 if OPTIONS.replace_verity_keyid:
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700633 ReplaceVerityKeyId(input_tf_zip, output_tf_zip,
634 OPTIONS.replace_verity_keyid[1])
Doug Zongker412c02f2014-02-13 10:58:24 -0800635
Tao Bao639118f2017-06-19 15:48:02 -0700636 # Replace the AVB signing keys, if any.
637 ReplaceAvbSigningKeys(misc_info)
638
Tao Bao19b02fe2019-10-09 00:04:28 -0700639 # Rewrite the props in AVB signing args.
640 if misc_info.get('avb_enable') == 'true':
641 RewriteAvbProps(misc_info)
642
Tao Bao46a59992017-06-05 11:55:16 -0700643 # Write back misc_info with the latest values.
644 ReplaceMiscInfoTxt(input_tf_zip, output_tf_zip, misc_info)
645
Doug Zongker8e931bf2009-04-06 15:21:45 -0700646
Robert Craig817c5742013-04-19 10:59:22 -0400647def ReplaceCerts(data):
Tao Bao66472632017-12-04 17:16:36 -0800648 """Replaces all the occurences of X.509 certs with the new ones.
Robert Craig817c5742013-04-19 10:59:22 -0400649
Tao Bao66472632017-12-04 17:16:36 -0800650 The mapping info is read from OPTIONS.key_map. Non-existent certificate will
651 be skipped. After the replacement, it additionally checks for duplicate
652 entries, which would otherwise fail the policy loading code in
653 frameworks/base/services/core/java/com/android/server/pm/SELinuxMMAC.java.
654
655 Args:
656 data: Input string that contains a set of X.509 certs.
657
658 Returns:
659 A string after the replacement.
660
661 Raises:
662 AssertionError: On finding duplicate entries.
663 """
Tao Baoa3705452019-06-24 15:33:41 -0700664 for old, new in OPTIONS.key_map.items():
Tao Bao66472632017-12-04 17:16:36 -0800665 if OPTIONS.verbose:
666 print(" Replacing %s.x509.pem with %s.x509.pem" % (old, new))
667
668 try:
669 with open(old + ".x509.pem") as old_fp:
670 old_cert16 = base64.b16encode(
Tao Baoa3705452019-06-24 15:33:41 -0700671 common.ParseCertificate(old_fp.read())).decode().lower()
Tao Bao66472632017-12-04 17:16:36 -0800672 with open(new + ".x509.pem") as new_fp:
673 new_cert16 = base64.b16encode(
Tao Baoa3705452019-06-24 15:33:41 -0700674 common.ParseCertificate(new_fp.read())).decode().lower()
Tao Bao66472632017-12-04 17:16:36 -0800675 except IOError as e:
676 if OPTIONS.verbose or e.errno != errno.ENOENT:
677 print(" Error accessing %s: %s.\nSkip replacing %s.x509.pem with "
678 "%s.x509.pem." % (e.filename, e.strerror, old, new))
679 continue
680
681 # Only match entire certs.
682 pattern = "\\b" + old_cert16 + "\\b"
683 (data, num) = re.subn(pattern, new_cert16, data, flags=re.IGNORECASE)
684
685 if OPTIONS.verbose:
686 print(" Replaced %d occurence(s) of %s.x509.pem with %s.x509.pem" % (
687 num, old, new))
688
689 # Verify that there're no duplicate entries after the replacement. Note that
690 # it's only checking entries with global seinfo at the moment (i.e. ignoring
691 # the ones with inner packages). (Bug: 69479366)
692 root = ElementTree.fromstring(data)
693 signatures = [signer.attrib['signature'] for signer in root.findall('signer')]
694 assert len(signatures) == len(set(signatures)), \
695 "Found duplicate entries after cert replacement: {}".format(data)
Robert Craig817c5742013-04-19 10:59:22 -0400696
697 return data
698
699
Doug Zongkerc09abc82010-01-11 13:09:15 -0800700def EditTags(tags):
Tao Baoa7054ee2017-12-08 14:42:16 -0800701 """Applies the edits to the tag string as specified in OPTIONS.tag_changes.
702
703 Args:
704 tags: The input string that contains comma-separated tags.
705
706 Returns:
707 The updated tags (comma-separated and sorted).
708 """
Doug Zongkerc09abc82010-01-11 13:09:15 -0800709 tags = set(tags.split(","))
710 for ch in OPTIONS.tag_changes:
711 if ch[0] == "-":
712 tags.discard(ch[1:])
713 elif ch[0] == "+":
714 tags.add(ch[1:])
715 return ",".join(sorted(tags))
716
717
Tao Baoa7054ee2017-12-08 14:42:16 -0800718def RewriteProps(data):
719 """Rewrites the system properties in the given string.
720
721 Each property is expected in 'key=value' format. The properties that contain
722 build tags (i.e. test-keys, dev-keys) will be updated accordingly by calling
723 EditTags().
724
725 Args:
726 data: Input string, separated by newlines.
727
728 Returns:
729 The string with modified properties.
730 """
Doug Zongker17aa9442009-04-17 10:15:58 -0700731 output = []
732 for line in data.split("\n"):
733 line = line.strip()
734 original_line = line
Michael Rungedc2661a2014-06-03 14:43:11 -0700735 if line and line[0] != '#' and "=" in line:
Doug Zongker17aa9442009-04-17 10:15:58 -0700736 key, value = line.split("=", 1)
Magnus Strandh234f4b42019-05-01 23:09:30 +0200737 if (key.startswith("ro.") and
738 key.endswith((".build.fingerprint", ".build.thumbprint"))):
Doug Zongkerc09abc82010-01-11 13:09:15 -0800739 pieces = value.split("/")
740 pieces[-1] = EditTags(pieces[-1])
741 value = "/".join(pieces)
Tao Baocb7ff772015-09-11 15:27:56 -0700742 elif key == "ro.bootimage.build.fingerprint":
743 pieces = value.split("/")
744 pieces[-1] = EditTags(pieces[-1])
745 value = "/".join(pieces)
Doug Zongker17aa9442009-04-17 10:15:58 -0700746 elif key == "ro.build.description":
Doug Zongkerc09abc82010-01-11 13:09:15 -0800747 pieces = value.split(" ")
Doug Zongker17aa9442009-04-17 10:15:58 -0700748 assert len(pieces) == 5
Doug Zongkerc09abc82010-01-11 13:09:15 -0800749 pieces[-1] = EditTags(pieces[-1])
750 value = " ".join(pieces)
Magnus Strandh234f4b42019-05-01 23:09:30 +0200751 elif key.startswith("ro.") and key.endswith(".build.tags"):
Doug Zongkerc09abc82010-01-11 13:09:15 -0800752 value = EditTags(value)
Doug Zongkera8608a72013-07-23 11:51:04 -0700753 elif key == "ro.build.display.id":
754 # change, eg, "JWR66N dev-keys" to "JWR66N"
755 value = value.split()
Michael Rungedc2661a2014-06-03 14:43:11 -0700756 if len(value) > 1 and value[-1].endswith("-keys"):
Andrew Boie73d5abb2013-12-11 12:42:03 -0800757 value.pop()
758 value = " ".join(value)
Doug Zongkerc09abc82010-01-11 13:09:15 -0800759 line = key + "=" + value
Doug Zongker17aa9442009-04-17 10:15:58 -0700760 if line != original_line:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800761 print(" replace: ", original_line)
762 print(" with: ", line)
Doug Zongker17aa9442009-04-17 10:15:58 -0700763 output.append(line)
764 return "\n".join(output) + "\n"
765
766
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700767def WriteOtacerts(output_zip, filename, keys):
768 """Constructs a zipfile from given keys; and writes it to output_zip.
769
770 Args:
771 output_zip: The output target_files zip.
772 filename: The archive name in the output zip.
773 keys: A list of public keys to use during OTA package verification.
774 """
Tao Baobb733882019-07-24 23:31:19 -0700775 temp_file = io.BytesIO()
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700776 certs_zip = zipfile.ZipFile(temp_file, "w")
777 for k in keys:
778 common.ZipWrite(certs_zip, k)
779 common.ZipClose(certs_zip)
780 common.ZipWriteStr(output_zip, filename, temp_file.getvalue())
781
782
Doug Zongker831840e2011-09-22 10:28:04 -0700783def ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info):
Doug Zongker8e931bf2009-04-06 15:21:45 -0700784 try:
785 keylist = input_tf_zip.read("META/otakeys.txt").split()
786 except KeyError:
T.R. Fullharta28acc62013-03-18 10:31:26 -0700787 raise common.ExternalError("can't read META/otakeys.txt from input")
Doug Zongker8e931bf2009-04-06 15:21:45 -0700788
Tao Baof718f902017-11-09 10:10:10 -0800789 extra_recovery_keys = misc_info.get("extra_recovery_keys")
Doug Zongkere121d6a2011-02-01 14:13:52 -0800790 if extra_recovery_keys:
791 extra_recovery_keys = [OPTIONS.key_map.get(k, k) + ".x509.pem"
792 for k in extra_recovery_keys.split()]
793 if extra_recovery_keys:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800794 print("extra recovery-only key(s): " + ", ".join(extra_recovery_keys))
Doug Zongkere121d6a2011-02-01 14:13:52 -0800795 else:
796 extra_recovery_keys = []
797
Doug Zongker8e931bf2009-04-06 15:21:45 -0700798 mapped_keys = []
799 for k in keylist:
800 m = re.match(r"^(.*)\.x509\.pem$", k)
801 if not m:
Doug Zongker412c02f2014-02-13 10:58:24 -0800802 raise common.ExternalError(
803 "can't parse \"%s\" from META/otakeys.txt" % (k,))
Doug Zongker8e931bf2009-04-06 15:21:45 -0700804 k = m.group(1)
805 mapped_keys.append(OPTIONS.key_map.get(k, k) + ".x509.pem")
806
Doug Zongkere05628c2009-08-20 17:38:42 -0700807 if mapped_keys:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800808 print("using:\n ", "\n ".join(mapped_keys))
809 print("for OTA package verification")
Doug Zongkere05628c2009-08-20 17:38:42 -0700810 else:
Doug Zongker831840e2011-09-22 10:28:04 -0700811 devkey = misc_info.get("default_system_dev_certificate",
Dan Willemsen0ab1be62019-04-09 21:35:37 -0700812 "build/make/target/product/security/testkey")
Tao Baof718f902017-11-09 10:10:10 -0800813 mapped_devkey = OPTIONS.key_map.get(devkey, devkey)
814 if mapped_devkey != devkey:
815 misc_info["default_system_dev_certificate"] = mapped_devkey
816 mapped_keys.append(mapped_devkey + ".x509.pem")
Tao Baoa80ed222016-06-16 14:41:24 -0700817 print("META/otakeys.txt has no keys; using %s for OTA package"
818 " verification." % (mapped_keys[0],))
Doug Zongker8e931bf2009-04-06 15:21:45 -0700819
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700820 # recovery now uses the same x509.pem version of the keys.
Doug Zongkere121d6a2011-02-01 14:13:52 -0800821 # extra_recovery_keys are used only in recovery.
Tom Cherry2929cad2018-09-20 11:04:37 -0700822 if misc_info.get("recovery_as_boot") == "true":
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700823 recovery_keys_location = "BOOT/RAMDISK/system/etc/security/otacerts.zip"
Tao Baoa80ed222016-06-16 14:41:24 -0700824 else:
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700825 recovery_keys_location = "RECOVERY/RAMDISK/system/etc/security/otacerts.zip"
826
827 WriteOtacerts(output_tf_zip, recovery_keys_location,
828 mapped_keys + extra_recovery_keys)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700829
830 # SystemUpdateActivity uses the x509.pem version of the keys, but
831 # put into a zipfile system/etc/security/otacerts.zip.
Doug Zongkere121d6a2011-02-01 14:13:52 -0800832 # We DO NOT include the extra_recovery_keys (if any) here.
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700833 WriteOtacerts(output_tf_zip, "SYSTEM/etc/security/otacerts.zip", mapped_keys)
Doug Zongkereef39442009-04-02 12:14:19 -0700834
Tao Baoa80ed222016-06-16 14:41:24 -0700835 # For A/B devices, update the payload verification key.
836 if misc_info.get("ab_update") == "true":
837 # Unlike otacerts.zip that may contain multiple keys, we can only specify
838 # ONE payload verification key.
839 if len(mapped_keys) > 1:
840 print("\n WARNING: Found more than one OTA keys; Using the first one"
841 " as payload verification key.\n\n")
842
Tao Bao0c28d2d2017-12-24 10:37:38 -0800843 print("Using %s for payload verification." % (mapped_keys[0],))
Tao Bao04e1f012018-02-04 12:13:35 -0800844 pubkey = common.ExtractPublicKey(mapped_keys[0])
Tao Bao13b69622016-07-06 15:28:59 -0700845 common.ZipWriteStr(
Tao Baoa80ed222016-06-16 14:41:24 -0700846 output_tf_zip,
Tao Bao13b69622016-07-06 15:28:59 -0700847 "SYSTEM/etc/update_engine/update-payload-key.pub.pem",
848 pubkey)
Alex Deymob3e8ce62016-08-04 16:06:12 -0700849 common.ZipWriteStr(
850 output_tf_zip,
Tao Bao696bb332018-08-17 16:27:01 -0700851 "BOOT/RAMDISK/system/etc/update_engine/update-payload-key.pub.pem",
Alex Deymob3e8ce62016-08-04 16:06:12 -0700852 pubkey)
Tao Baoa80ed222016-06-16 14:41:24 -0700853
Tao Bao8adcfd12016-06-17 17:01:22 -0700854
Tao Bao0c28d2d2017-12-24 10:37:38 -0800855def ReplaceVerityPublicKey(output_zip, filename, key_path):
856 """Replaces the verity public key at the given path in the given zip.
857
858 Args:
859 output_zip: The output target_files zip.
860 filename: The archive name in the output zip.
861 key_path: The path to the public key.
862 """
863 print("Replacing verity public key with %s" % (key_path,))
864 common.ZipWrite(output_zip, key_path, arcname=filename)
Geremy Condraf19b3652014-07-29 17:54:54 -0700865
Tao Bao8adcfd12016-06-17 17:01:22 -0700866
Tao Bao46a59992017-06-05 11:55:16 -0700867def ReplaceVerityPrivateKey(misc_info, key_path):
Tao Bao0c28d2d2017-12-24 10:37:38 -0800868 """Replaces the verity private key in misc_info dict.
869
870 Args:
871 misc_info: The info dict.
872 key_path: The path to the private key in PKCS#8 format.
873 """
874 print("Replacing verity private key with %s" % (key_path,))
Andrew Boied083f0b2014-09-15 16:01:07 -0700875 misc_info["verity_key"] = key_path
Doug Zongkereef39442009-04-02 12:14:19 -0700876
Tao Bao8adcfd12016-06-17 17:01:22 -0700877
Tao Baoe838d142017-12-23 23:44:48 -0800878def ReplaceVerityKeyId(input_zip, output_zip, key_path):
879 """Replaces the veritykeyid parameter in BOOT/cmdline.
880
881 Args:
882 input_zip: The input target_files zip, which should be already open.
883 output_zip: The output target_files zip, which should be already open and
884 writable.
885 key_path: The path to the PEM encoded X.509 certificate.
886 """
Tao Baoa3705452019-06-24 15:33:41 -0700887 in_cmdline = input_zip.read("BOOT/cmdline").decode()
Tao Baoe838d142017-12-23 23:44:48 -0800888 # Copy in_cmdline to output_zip if veritykeyid is not present.
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700889 if "veritykeyid" not in in_cmdline:
Tao Baoe838d142017-12-23 23:44:48 -0800890 common.ZipWriteStr(output_zip, "BOOT/cmdline", in_cmdline)
891 return
892
Tao Bao0c28d2d2017-12-24 10:37:38 -0800893 out_buffer = []
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700894 for param in in_cmdline.split():
Tao Baoe838d142017-12-23 23:44:48 -0800895 if "veritykeyid" not in param:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800896 out_buffer.append(param)
Tao Baoe838d142017-12-23 23:44:48 -0800897 continue
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700898
Tao Baoe838d142017-12-23 23:44:48 -0800899 # Extract keyid using openssl command.
900 p = common.Run(["openssl", "x509", "-in", key_path, "-text"],
Tao Baode1d4792018-02-20 10:05:46 -0800901 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
Tao Baoe838d142017-12-23 23:44:48 -0800902 keyid, stderr = p.communicate()
903 assert p.returncode == 0, "Failed to dump certificate: {}".format(stderr)
904 keyid = re.search(
905 r'keyid:([0-9a-fA-F:]*)', keyid).group(1).replace(':', '').lower()
906 print("Replacing verity keyid with {}".format(keyid))
907 out_buffer.append("veritykeyid=id:%s" % (keyid,))
908
909 out_cmdline = ' '.join(out_buffer).strip() + '\n'
910 common.ZipWriteStr(output_zip, "BOOT/cmdline", out_cmdline)
Tao Bao46a59992017-06-05 11:55:16 -0700911
912
913def ReplaceMiscInfoTxt(input_zip, output_zip, misc_info):
914 """Replaces META/misc_info.txt.
915
916 Only writes back the ones in the original META/misc_info.txt. Because the
917 current in-memory dict contains additional items computed at runtime.
918 """
919 misc_info_old = common.LoadDictionaryFromLines(
Tao Baoa3705452019-06-24 15:33:41 -0700920 input_zip.read('META/misc_info.txt').decode().split('\n'))
Tao Bao46a59992017-06-05 11:55:16 -0700921 items = []
922 for key in sorted(misc_info):
923 if key in misc_info_old:
924 items.append('%s=%s' % (key, misc_info[key]))
925 common.ZipWriteStr(output_zip, "META/misc_info.txt", '\n'.join(items))
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700926
Tao Bao8adcfd12016-06-17 17:01:22 -0700927
Tao Bao639118f2017-06-19 15:48:02 -0700928def ReplaceAvbSigningKeys(misc_info):
929 """Replaces the AVB signing keys."""
930
Tao Bao639118f2017-06-19 15:48:02 -0700931 def ReplaceAvbPartitionSigningKey(partition):
932 key = OPTIONS.avb_keys.get(partition)
933 if not key:
934 return
935
936 algorithm = OPTIONS.avb_algorithms.get(partition)
937 assert algorithm, 'Missing AVB signing algorithm for %s' % (partition,)
938
Tao Bao0c28d2d2017-12-24 10:37:38 -0800939 print('Replacing AVB signing key for %s with "%s" (%s)' % (
940 partition, key, algorithm))
Tao Bao639118f2017-06-19 15:48:02 -0700941 misc_info['avb_' + partition + '_algorithm'] = algorithm
942 misc_info['avb_' + partition + '_key_path'] = key
943
944 extra_args = OPTIONS.avb_extra_args.get(partition)
945 if extra_args:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800946 print('Setting extra AVB signing args for %s to "%s"' % (
947 partition, extra_args))
Tao Bao639118f2017-06-19 15:48:02 -0700948 args_key = AVB_FOOTER_ARGS_BY_PARTITION[partition]
949 misc_info[args_key] = (misc_info.get(args_key, '') + ' ' + extra_args)
950
951 for partition in AVB_FOOTER_ARGS_BY_PARTITION:
952 ReplaceAvbPartitionSigningKey(partition)
953
954
Tao Bao19b02fe2019-10-09 00:04:28 -0700955def RewriteAvbProps(misc_info):
956 """Rewrites the props in AVB signing args."""
957 for partition, args_key in AVB_FOOTER_ARGS_BY_PARTITION.items():
958 args = misc_info.get(args_key)
959 if not args:
960 continue
961
962 tokens = []
963 changed = False
964 for token in args.split(' '):
965 fingerprint_key = 'com.android.build.{}.fingerprint'.format(partition)
966 if not token.startswith(fingerprint_key):
967 tokens.append(token)
968 continue
969 prefix, tag = token.rsplit('/', 1)
970 tokens.append('{}/{}'.format(prefix, EditTags(tag)))
971 changed = True
972
973 if changed:
974 result = ' '.join(tokens)
975 print('Rewriting AVB prop for {}:\n'.format(partition))
976 print(' replace: {}'.format(args))
977 print(' with: {}'.format(result))
978 misc_info[args_key] = result
979
980
Doug Zongker831840e2011-09-22 10:28:04 -0700981def BuildKeyMap(misc_info, key_mapping_options):
982 for s, d in key_mapping_options:
983 if s is None: # -d option
984 devkey = misc_info.get("default_system_dev_certificate",
Dan Willemsen0ab1be62019-04-09 21:35:37 -0700985 "build/make/target/product/security/testkey")
Doug Zongker831840e2011-09-22 10:28:04 -0700986 devkeydir = os.path.dirname(devkey)
987
988 OPTIONS.key_map.update({
989 devkeydir + "/testkey": d + "/releasekey",
990 devkeydir + "/devkey": d + "/releasekey",
991 devkeydir + "/media": d + "/media",
992 devkeydir + "/shared": d + "/shared",
993 devkeydir + "/platform": d + "/platform",
994 })
995 else:
996 OPTIONS.key_map[s] = d
997
998
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800999def GetApiLevelAndCodename(input_tf_zip):
Tao Baoa3705452019-06-24 15:33:41 -07001000 data = input_tf_zip.read("SYSTEM/build.prop").decode()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001001 api_level = None
1002 codename = None
1003 for line in data.split("\n"):
1004 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001005 if line and line[0] != '#' and "=" in line:
1006 key, value = line.split("=", 1)
1007 key = key.strip()
1008 if key == "ro.build.version.sdk":
1009 api_level = int(value.strip())
1010 elif key == "ro.build.version.codename":
1011 codename = value.strip()
1012
1013 if api_level is None:
1014 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
1015 if codename is None:
1016 raise ValueError("No ro.build.version.codename in SYSTEM/build.prop")
1017
1018 return (api_level, codename)
1019
1020
1021def GetCodenameToApiLevelMap(input_tf_zip):
Tao Baoa3705452019-06-24 15:33:41 -07001022 data = input_tf_zip.read("SYSTEM/build.prop").decode()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001023 api_level = None
1024 codenames = None
1025 for line in data.split("\n"):
1026 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001027 if line and line[0] != '#' and "=" in line:
1028 key, value = line.split("=", 1)
1029 key = key.strip()
1030 if key == "ro.build.version.sdk":
1031 api_level = int(value.strip())
1032 elif key == "ro.build.version.all_codenames":
1033 codenames = value.strip().split(",")
1034
1035 if api_level is None:
1036 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
1037 if codenames is None:
1038 raise ValueError("No ro.build.version.all_codenames in SYSTEM/build.prop")
1039
Tao Baoa3705452019-06-24 15:33:41 -07001040 result = {}
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001041 for codename in codenames:
1042 codename = codename.strip()
Tao Baobadceb22019-03-15 09:33:43 -07001043 if codename:
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001044 result[codename] = api_level
1045 return result
1046
1047
Tao Baoaa7e9932019-03-15 09:37:01 -07001048def ReadApexKeysInfo(tf_zip):
1049 """Parses the APEX keys info from a given target-files zip.
1050
1051 Given a target-files ZipFile, parses the META/apexkeys.txt entry and returns a
1052 dict that contains the mapping from APEX names (e.g. com.android.tzdata) to a
1053 tuple of (payload_key, container_key).
1054
1055 Args:
1056 tf_zip: The input target_files ZipFile (already open).
1057
1058 Returns:
1059 (payload_key, container_key): payload_key contains the path to the payload
1060 signing key; container_key contains the path to the container signing
1061 key.
1062 """
1063 keys = {}
Tao Baoa3705452019-06-24 15:33:41 -07001064 for line in tf_zip.read('META/apexkeys.txt').decode().split('\n'):
Tao Baoaa7e9932019-03-15 09:37:01 -07001065 line = line.strip()
1066 if not line:
1067 continue
1068 matches = re.match(
1069 r'^name="(?P<NAME>.*)"\s+'
1070 r'public_key="(?P<PAYLOAD_PUBLIC_KEY>.*)"\s+'
1071 r'private_key="(?P<PAYLOAD_PRIVATE_KEY>.*)"\s+'
1072 r'container_certificate="(?P<CONTAINER_CERT>.*)"\s+'
1073 r'container_private_key="(?P<CONTAINER_PRIVATE_KEY>.*)"$',
1074 line)
1075 if not matches:
1076 continue
1077
1078 name = matches.group('NAME')
Tao Baoaa7e9932019-03-15 09:37:01 -07001079 payload_private_key = matches.group("PAYLOAD_PRIVATE_KEY")
1080
1081 def CompareKeys(pubkey, pubkey_suffix, privkey, privkey_suffix):
1082 pubkey_suffix_len = len(pubkey_suffix)
1083 privkey_suffix_len = len(privkey_suffix)
1084 return (pubkey.endswith(pubkey_suffix) and
1085 privkey.endswith(privkey_suffix) and
1086 pubkey[:-pubkey_suffix_len] == privkey[:-privkey_suffix_len])
1087
Tao Bao6d9e3da2019-03-26 12:59:25 -07001088 # Sanity check on the container key names, as we'll carry them without the
1089 # extensions. This doesn't apply to payload keys though, which we will use
1090 # full names only.
Tao Baoaa7e9932019-03-15 09:37:01 -07001091 container_cert = matches.group("CONTAINER_CERT")
1092 container_private_key = matches.group("CONTAINER_PRIVATE_KEY")
Tao Baof454c3a2019-04-24 23:53:42 -07001093 if container_cert == 'PRESIGNED' and container_private_key == 'PRESIGNED':
1094 container_key = 'PRESIGNED'
1095 elif CompareKeys(
Tao Baoaa7e9932019-03-15 09:37:01 -07001096 container_cert, OPTIONS.public_key_suffix,
1097 container_private_key, OPTIONS.private_key_suffix):
Tao Baof454c3a2019-04-24 23:53:42 -07001098 container_key = container_cert[:-len(OPTIONS.public_key_suffix)]
1099 else:
Tao Baoaa7e9932019-03-15 09:37:01 -07001100 raise ValueError("Failed to parse container keys: \n{}".format(line))
1101
Tao Baof454c3a2019-04-24 23:53:42 -07001102 keys[name] = (payload_private_key, container_key)
Tao Baoaa7e9932019-03-15 09:37:01 -07001103
1104 return keys
1105
1106
Doug Zongkereef39442009-04-02 12:14:19 -07001107def main(argv):
1108
Doug Zongker831840e2011-09-22 10:28:04 -07001109 key_mapping_options = []
1110
Doug Zongkereef39442009-04-02 12:14:19 -07001111 def option_handler(o, a):
Doug Zongker05d3dea2009-06-22 11:32:31 -07001112 if o in ("-e", "--extra_apks"):
Doug Zongkereef39442009-04-02 12:14:19 -07001113 names, key = a.split("=")
1114 names = names.split(",")
1115 for n in names:
1116 OPTIONS.extra_apks[n] = key
Tao Baoaa7e9932019-03-15 09:37:01 -07001117 elif o == "--extra_apex_payload_key":
1118 apex_name, key = a.split("=")
1119 OPTIONS.extra_apex_payload_keys[apex_name] = key
Tao Bao93c2a012018-06-19 12:19:35 -07001120 elif o == "--skip_apks_with_path_prefix":
1121 # Sanity check the prefix, which must be in all upper case.
1122 prefix = a.split('/')[0]
1123 if not prefix or prefix != prefix.upper():
1124 raise ValueError("Invalid path prefix '%s'" % (a,))
1125 OPTIONS.skip_apks_with_path_prefix.add(a)
Doug Zongkereef39442009-04-02 12:14:19 -07001126 elif o in ("-d", "--default_key_mappings"):
Doug Zongker831840e2011-09-22 10:28:04 -07001127 key_mapping_options.append((None, a))
Doug Zongkereef39442009-04-02 12:14:19 -07001128 elif o in ("-k", "--key_mapping"):
Doug Zongker831840e2011-09-22 10:28:04 -07001129 key_mapping_options.append(a.split("=", 1))
Doug Zongker8e931bf2009-04-06 15:21:45 -07001130 elif o in ("-o", "--replace_ota_keys"):
1131 OPTIONS.replace_ota_keys = True
Doug Zongkerae877012009-04-21 10:04:51 -07001132 elif o in ("-t", "--tag_changes"):
1133 new = []
1134 for i in a.split(","):
1135 i = i.strip()
1136 if not i or i[0] not in "-+":
1137 raise ValueError("Bad tag change '%s'" % (i,))
1138 new.append(i[0] + i[1:].strip())
1139 OPTIONS.tag_changes = tuple(new)
Geremy Condraf19b3652014-07-29 17:54:54 -07001140 elif o == "--replace_verity_public_key":
1141 OPTIONS.replace_verity_public_key = (True, a)
1142 elif o == "--replace_verity_private_key":
1143 OPTIONS.replace_verity_private_key = (True, a)
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001144 elif o == "--replace_verity_keyid":
1145 OPTIONS.replace_verity_keyid = (True, a)
Tao Bao639118f2017-06-19 15:48:02 -07001146 elif o == "--avb_vbmeta_key":
1147 OPTIONS.avb_keys['vbmeta'] = a
1148 elif o == "--avb_vbmeta_algorithm":
1149 OPTIONS.avb_algorithms['vbmeta'] = a
1150 elif o == "--avb_vbmeta_extra_args":
1151 OPTIONS.avb_extra_args['vbmeta'] = a
1152 elif o == "--avb_boot_key":
1153 OPTIONS.avb_keys['boot'] = a
1154 elif o == "--avb_boot_algorithm":
1155 OPTIONS.avb_algorithms['boot'] = a
1156 elif o == "--avb_boot_extra_args":
1157 OPTIONS.avb_extra_args['boot'] = a
1158 elif o == "--avb_dtbo_key":
1159 OPTIONS.avb_keys['dtbo'] = a
1160 elif o == "--avb_dtbo_algorithm":
1161 OPTIONS.avb_algorithms['dtbo'] = a
1162 elif o == "--avb_dtbo_extra_args":
1163 OPTIONS.avb_extra_args['dtbo'] = a
1164 elif o == "--avb_system_key":
1165 OPTIONS.avb_keys['system'] = a
1166 elif o == "--avb_system_algorithm":
1167 OPTIONS.avb_algorithms['system'] = a
1168 elif o == "--avb_system_extra_args":
1169 OPTIONS.avb_extra_args['system'] = a
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001170 elif o == "--avb_system_other_key":
1171 OPTIONS.avb_keys['system_other'] = a
1172 elif o == "--avb_system_other_algorithm":
1173 OPTIONS.avb_algorithms['system_other'] = a
1174 elif o == "--avb_system_other_extra_args":
1175 OPTIONS.avb_extra_args['system_other'] = a
Tao Bao639118f2017-06-19 15:48:02 -07001176 elif o == "--avb_vendor_key":
1177 OPTIONS.avb_keys['vendor'] = a
1178 elif o == "--avb_vendor_algorithm":
1179 OPTIONS.avb_algorithms['vendor'] = a
1180 elif o == "--avb_vendor_extra_args":
1181 OPTIONS.avb_extra_args['vendor'] = a
Tao Baod6085d62019-05-06 12:55:42 -07001182 elif o == "--avb_vbmeta_system_key":
1183 OPTIONS.avb_keys['vbmeta_system'] = a
1184 elif o == "--avb_vbmeta_system_algorithm":
1185 OPTIONS.avb_algorithms['vbmeta_system'] = a
1186 elif o == "--avb_vbmeta_system_extra_args":
1187 OPTIONS.avb_extra_args['vbmeta_system'] = a
1188 elif o == "--avb_vbmeta_vendor_key":
1189 OPTIONS.avb_keys['vbmeta_vendor'] = a
1190 elif o == "--avb_vbmeta_vendor_algorithm":
1191 OPTIONS.avb_algorithms['vbmeta_vendor'] = a
1192 elif o == "--avb_vbmeta_vendor_extra_args":
1193 OPTIONS.avb_extra_args['vbmeta_vendor'] = a
Tao Baoaa7e9932019-03-15 09:37:01 -07001194 elif o == "--avb_apex_extra_args":
1195 OPTIONS.avb_extra_args['apex'] = a
Doug Zongkereef39442009-04-02 12:14:19 -07001196 else:
1197 return False
1198 return True
1199
Tao Bao639118f2017-06-19 15:48:02 -07001200 args = common.ParseOptions(
1201 argv, __doc__,
1202 extra_opts="e:d:k:ot:",
1203 extra_long_opts=[
Tao Bao0c28d2d2017-12-24 10:37:38 -08001204 "extra_apks=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001205 "extra_apex_payload_key=",
Tao Bao93c2a012018-06-19 12:19:35 -07001206 "skip_apks_with_path_prefix=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001207 "default_key_mappings=",
1208 "key_mapping=",
1209 "replace_ota_keys",
1210 "tag_changes=",
1211 "replace_verity_public_key=",
1212 "replace_verity_private_key=",
1213 "replace_verity_keyid=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001214 "avb_apex_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001215 "avb_vbmeta_algorithm=",
1216 "avb_vbmeta_key=",
1217 "avb_vbmeta_extra_args=",
1218 "avb_boot_algorithm=",
1219 "avb_boot_key=",
1220 "avb_boot_extra_args=",
1221 "avb_dtbo_algorithm=",
1222 "avb_dtbo_key=",
1223 "avb_dtbo_extra_args=",
1224 "avb_system_algorithm=",
1225 "avb_system_key=",
1226 "avb_system_extra_args=",
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001227 "avb_system_other_algorithm=",
1228 "avb_system_other_key=",
1229 "avb_system_other_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001230 "avb_vendor_algorithm=",
1231 "avb_vendor_key=",
1232 "avb_vendor_extra_args=",
Tao Baod6085d62019-05-06 12:55:42 -07001233 "avb_vbmeta_system_algorithm=",
1234 "avb_vbmeta_system_key=",
1235 "avb_vbmeta_system_extra_args=",
1236 "avb_vbmeta_vendor_algorithm=",
1237 "avb_vbmeta_vendor_key=",
1238 "avb_vbmeta_vendor_extra_args=",
Tao Bao639118f2017-06-19 15:48:02 -07001239 ],
1240 extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001241
1242 if len(args) != 2:
1243 common.Usage(__doc__)
1244 sys.exit(1)
1245
Tao Baobadceb22019-03-15 09:33:43 -07001246 common.InitLogging()
1247
Doug Zongkereef39442009-04-02 12:14:19 -07001248 input_zip = zipfile.ZipFile(args[0], "r")
Tao Bao2b8f4892017-06-13 12:54:58 -07001249 output_zip = zipfile.ZipFile(args[1], "w",
1250 compression=zipfile.ZIP_DEFLATED,
1251 allowZip64=True)
Doug Zongkereef39442009-04-02 12:14:19 -07001252
Doug Zongker831840e2011-09-22 10:28:04 -07001253 misc_info = common.LoadInfoDict(input_zip)
1254
1255 BuildKeyMap(misc_info, key_mapping_options)
1256
Tao Baoaa7e9932019-03-15 09:37:01 -07001257 apk_keys_info, compressed_extension = common.ReadApkCerts(input_zip)
1258 apk_keys = GetApkCerts(apk_keys_info)
Doug Zongkereb338ef2009-05-20 16:50:49 -07001259
Tao Baoaa7e9932019-03-15 09:37:01 -07001260 apex_keys_info = ReadApexKeysInfo(input_zip)
1261 apex_keys = GetApexKeys(apex_keys_info, apk_keys)
1262
1263 CheckApkAndApexKeysAvailable(
1264 input_zip,
1265 set(apk_keys.keys()) | set(apex_keys.keys()),
Tao Baoe1343992019-03-19 12:24:03 -07001266 compressed_extension,
1267 apex_keys)
Tao Baoaa7e9932019-03-15 09:37:01 -07001268
1269 key_passwords = common.GetKeyPasswords(
1270 set(apk_keys.values()) | set(itertools.chain(*apex_keys.values())))
Tao Bao9aa4b9b2016-09-29 17:53:56 -07001271 platform_api_level, _ = GetApiLevelAndCodename(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001272 codename_to_api_level_map = GetCodenameToApiLevelMap(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001273
Doug Zongker412c02f2014-02-13 10:58:24 -08001274 ProcessTargetFiles(input_zip, output_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -07001275 apk_keys, apex_keys, key_passwords,
1276 platform_api_level, codename_to_api_level_map,
Narayan Kamatha07bf042017-08-14 14:49:21 +01001277 compressed_extension)
Doug Zongker8e931bf2009-04-06 15:21:45 -07001278
Tao Bao2ed665a2015-04-01 11:21:55 -07001279 common.ZipClose(input_zip)
1280 common.ZipClose(output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001281
Tianjie Xub48589a2016-08-03 19:21:52 -07001282 # Skip building userdata.img and cache.img when signing the target files.
Tianjie Xu616fbeb2017-05-23 14:51:02 -07001283 new_args = ["--is_signing"]
1284 # add_img_to_target_files builds the system image from scratch, so the
1285 # recovery patch is guaranteed to be regenerated there.
1286 if OPTIONS.rebuild_recovery:
1287 new_args.append("--rebuild_recovery")
1288 new_args.append(args[1])
Tianjie Xub48589a2016-08-03 19:21:52 -07001289 add_img_to_target_files.main(new_args)
Doug Zongker3c84f562014-07-31 11:06:30 -07001290
Tao Bao0c28d2d2017-12-24 10:37:38 -08001291 print("done.")
Doug Zongkereef39442009-04-02 12:14:19 -07001292
1293
1294if __name__ == '__main__':
1295 try:
1296 main(sys.argv[1:])
Tao Bao0c28d2d2017-12-24 10:37:38 -08001297 except common.ExternalError as e:
1298 print("\n ERROR: %s\n" % (e,))
Doug Zongkereef39442009-04-02 12:14:19 -07001299 sys.exit(1)
Tao Bao639118f2017-06-19 15:48:02 -07001300 finally:
1301 common.Cleanup()