blob: 710147bb231c5b7ec3755cecf7078317c6d5f0ec [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
Narayan Kamatha07bf042017-08-14 14:49:21 +0100156def GetApkCerts(certmap):
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800157 # apply the key remapping to the contents of the file
Tao Baoa3705452019-06-24 15:33:41 -0700158 for apk, cert in certmap.items():
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800159 certmap[apk] = OPTIONS.key_map.get(cert, cert)
160
161 # apply all the -e options, overriding anything in the file
Tao Baoa3705452019-06-24 15:33:41 -0700162 for apk, cert in OPTIONS.extra_apks.items():
Doug Zongkerdecf9952009-12-15 17:27:49 -0800163 if not cert:
164 cert = "PRESIGNED"
Doug Zongkerad88c7c2009-04-14 12:34:27 -0700165 certmap[apk] = OPTIONS.key_map.get(cert, cert)
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800166
Doug Zongkereef39442009-04-02 12:14:19 -0700167 return certmap
168
169
Tao Baoaa7e9932019-03-15 09:37:01 -0700170def GetApexKeys(keys_info, key_map):
171 """Gets APEX payload and container signing keys by applying the mapping rules.
172
Tao Baoe1343992019-03-19 12:24:03 -0700173 Presigned payload / container keys will be set accordingly.
Tao Baoaa7e9932019-03-15 09:37:01 -0700174
175 Args:
176 keys_info: A dict that maps from APEX filenames to a tuple of (payload_key,
177 container_key).
178 key_map: A dict that overrides the keys, specified via command-line input.
179
180 Returns:
181 A dict that contains the updated APEX key mapping, which should be used for
182 the current signing.
Tao Baof98fa102019-04-24 14:51:25 -0700183
184 Raises:
185 AssertionError: On invalid container / payload key overrides.
Tao Baoaa7e9932019-03-15 09:37:01 -0700186 """
187 # Apply all the --extra_apex_payload_key options to override the payload
188 # signing keys in the given keys_info.
189 for apex, key in OPTIONS.extra_apex_payload_keys.items():
Tao Baoe1343992019-03-19 12:24:03 -0700190 if not key:
191 key = 'PRESIGNED'
Tao Bao34223092019-07-11 11:52:52 -0700192 if apex not in keys_info:
193 logger.warning('Failed to find %s in target_files; Ignored', apex)
194 continue
Tao Baoaa7e9932019-03-15 09:37:01 -0700195 keys_info[apex] = (key, keys_info[apex][1])
196
197 # Apply the key remapping to container keys.
198 for apex, (payload_key, container_key) in keys_info.items():
199 keys_info[apex] = (payload_key, key_map.get(container_key, container_key))
200
201 # Apply all the --extra_apks options to override the container keys.
202 for apex, key in OPTIONS.extra_apks.items():
203 # Skip non-APEX containers.
204 if apex not in keys_info:
205 continue
Tao Baoe1343992019-03-19 12:24:03 -0700206 if not key:
207 key = 'PRESIGNED'
Tao Baofa9de0a2019-03-18 10:24:17 -0700208 keys_info[apex] = (keys_info[apex][0], key_map.get(key, key))
Tao Baoaa7e9932019-03-15 09:37:01 -0700209
Tao Baof98fa102019-04-24 14:51:25 -0700210 # A PRESIGNED container entails a PRESIGNED payload. Apply this to all the
211 # APEX key pairs. However, a PRESIGNED container with non-PRESIGNED payload
212 # (overridden via commandline) indicates a config error, which should not be
213 # allowed.
214 for apex, (payload_key, container_key) in keys_info.items():
215 if container_key != 'PRESIGNED':
216 continue
217 if apex in OPTIONS.extra_apex_payload_keys:
218 payload_override = OPTIONS.extra_apex_payload_keys[apex]
219 assert payload_override == '', \
220 ("Invalid APEX key overrides: {} has PRESIGNED container but "
221 "non-PRESIGNED payload key {}").format(apex, payload_override)
222 if payload_key != 'PRESIGNED':
223 print(
224 "Setting {} payload as PRESIGNED due to PRESIGNED container".format(
225 apex))
226 keys_info[apex] = ('PRESIGNED', 'PRESIGNED')
227
Tao Baoaa7e9932019-03-15 09:37:01 -0700228 return keys_info
229
230
Tao Bao93c2a012018-06-19 12:19:35 -0700231def GetApkFileInfo(filename, compressed_extension, skipped_prefixes):
Tao Bao11f955c2018-06-19 12:19:35 -0700232 """Returns the APK info based on the given filename.
233
234 Checks if the given filename (with path) looks like an APK file, by taking the
Tao Bao93c2a012018-06-19 12:19:35 -0700235 compressed extension into consideration. If it appears to be an APK file,
236 further checks if the APK file should be skipped when signing, based on the
237 given path prefixes.
Tao Bao11f955c2018-06-19 12:19:35 -0700238
239 Args:
240 filename: Path to the file.
241 compressed_extension: The extension string of compressed APKs (e.g. ".gz"),
242 or None if there's no compressed APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700243 skipped_prefixes: A set/list/tuple of the path prefixes to be skipped.
Tao Bao11f955c2018-06-19 12:19:35 -0700244
245 Returns:
Tao Bao93c2a012018-06-19 12:19:35 -0700246 (is_apk, is_compressed, should_be_skipped): is_apk indicates whether the
247 given filename is an APK file. is_compressed indicates whether the APK file
248 is compressed (only meaningful when is_apk is True). should_be_skipped
249 indicates whether the filename matches any of the given prefixes to be
250 skipped.
Tao Bao11f955c2018-06-19 12:19:35 -0700251
252 Raises:
Tao Bao93c2a012018-06-19 12:19:35 -0700253 AssertionError: On invalid compressed_extension or skipped_prefixes inputs.
Tao Bao11f955c2018-06-19 12:19:35 -0700254 """
255 assert compressed_extension is None or compressed_extension.startswith('.'), \
256 "Invalid compressed_extension arg: '{}'".format(compressed_extension)
257
Tao Bao93c2a012018-06-19 12:19:35 -0700258 # skipped_prefixes should be one of set/list/tuple types. Other types such as
259 # str shouldn't be accepted.
Tao Baobadceb22019-03-15 09:33:43 -0700260 assert isinstance(skipped_prefixes, (set, list, tuple)), \
261 "Invalid skipped_prefixes input type: {}".format(type(skipped_prefixes))
Tao Bao93c2a012018-06-19 12:19:35 -0700262
Tao Bao11f955c2018-06-19 12:19:35 -0700263 compressed_apk_extension = (
264 ".apk" + compressed_extension if compressed_extension else None)
265 is_apk = (filename.endswith(".apk") or
266 (compressed_apk_extension and
267 filename.endswith(compressed_apk_extension)))
268 if not is_apk:
Tao Bao93c2a012018-06-19 12:19:35 -0700269 return (False, False, False)
Tao Bao11f955c2018-06-19 12:19:35 -0700270
271 is_compressed = (compressed_apk_extension and
272 filename.endswith(compressed_apk_extension))
Tao Bao93c2a012018-06-19 12:19:35 -0700273 should_be_skipped = filename.startswith(tuple(skipped_prefixes))
274 return (True, is_compressed, should_be_skipped)
Tao Bao11f955c2018-06-19 12:19:35 -0700275
276
Tao Baoaa7e9932019-03-15 09:37:01 -0700277def CheckApkAndApexKeysAvailable(input_tf_zip, known_keys,
Tao Baoe1343992019-03-19 12:24:03 -0700278 compressed_extension, apex_keys):
Tao Baoaa7e9932019-03-15 09:37:01 -0700279 """Checks that all the APKs and APEXes have keys specified.
Tao Bao11f955c2018-06-19 12:19:35 -0700280
281 Args:
282 input_tf_zip: An open target_files zip file.
Tao Baoaa7e9932019-03-15 09:37:01 -0700283 known_keys: A set of APKs and APEXes that have known signing keys.
Tao Bao11f955c2018-06-19 12:19:35 -0700284 compressed_extension: The extension string of compressed APKs, such as
Tao Baoaa7e9932019-03-15 09:37:01 -0700285 '.gz', or None if there's no compressed APKs.
Tao Baoe1343992019-03-19 12:24:03 -0700286 apex_keys: A dict that contains the key mapping from APEX name to
287 (payload_key, container_key).
Tao Bao11f955c2018-06-19 12:19:35 -0700288
289 Raises:
Tao Baoaa7e9932019-03-15 09:37:01 -0700290 AssertionError: On finding unknown APKs and APEXes.
Tao Bao11f955c2018-06-19 12:19:35 -0700291 """
Tao Baoaa7e9932019-03-15 09:37:01 -0700292 unknown_files = []
Doug Zongkereb338ef2009-05-20 16:50:49 -0700293 for info in input_tf_zip.infolist():
Tao Baoaa7e9932019-03-15 09:37:01 -0700294 # Handle APEXes first, e.g. SYSTEM/apex/com.android.tzdata.apex.
295 if (info.filename.startswith('SYSTEM/apex') and
296 info.filename.endswith('.apex')):
297 name = os.path.basename(info.filename)
298 if name not in known_keys:
299 unknown_files.append(name)
300 continue
301
302 # And APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700303 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
304 info.filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
305 if not is_apk or should_be_skipped:
Tao Bao11f955c2018-06-19 12:19:35 -0700306 continue
Tao Baoaa7e9932019-03-15 09:37:01 -0700307
Tao Bao11f955c2018-06-19 12:19:35 -0700308 name = os.path.basename(info.filename)
309 if is_compressed:
310 name = name[:-len(compressed_extension)]
Tao Baoaa7e9932019-03-15 09:37:01 -0700311 if name not in known_keys:
312 unknown_files.append(name)
Tao Bao11f955c2018-06-19 12:19:35 -0700313
Tao Baoaa7e9932019-03-15 09:37:01 -0700314 assert not unknown_files, \
Tao Bao11f955c2018-06-19 12:19:35 -0700315 ("No key specified for:\n {}\n"
316 "Use '-e <apkname>=' to specify a key (which may be an empty string to "
Tao Baoaa7e9932019-03-15 09:37:01 -0700317 "not sign this apk).".format("\n ".join(unknown_files)))
Doug Zongkereb338ef2009-05-20 16:50:49 -0700318
Tao Baoe1343992019-03-19 12:24:03 -0700319 # For all the APEXes, double check that we won't have an APEX that has only
Tao Baof98fa102019-04-24 14:51:25 -0700320 # one of the payload / container keys set. Note that non-PRESIGNED container
321 # with PRESIGNED payload could be allowed but currently unsupported. It would
322 # require changing SignApex implementation.
Tao Baoe1343992019-03-19 12:24:03 -0700323 if not apex_keys:
324 return
325
326 invalid_apexes = []
327 for info in input_tf_zip.infolist():
328 if (not info.filename.startswith('SYSTEM/apex') or
329 not info.filename.endswith('.apex')):
330 continue
331
332 name = os.path.basename(info.filename)
333 (payload_key, container_key) = apex_keys[name]
334 if ((payload_key in common.SPECIAL_CERT_STRINGS and
335 container_key not in common.SPECIAL_CERT_STRINGS) or
336 (payload_key not in common.SPECIAL_CERT_STRINGS and
337 container_key in common.SPECIAL_CERT_STRINGS)):
338 invalid_apexes.append(
339 "{}: payload_key {}, container_key {}".format(
340 name, payload_key, container_key))
341
342 assert not invalid_apexes, \
343 "Invalid APEX keys specified:\n {}\n".format(
344 "\n ".join(invalid_apexes))
345
Doug Zongkereb338ef2009-05-20 16:50:49 -0700346
Narayan Kamatha07bf042017-08-14 14:49:21 +0100347def SignApk(data, keyname, pw, platform_api_level, codename_to_api_level_map,
348 is_compressed):
Doug Zongkereef39442009-04-02 12:14:19 -0700349 unsigned = tempfile.NamedTemporaryFile()
350 unsigned.write(data)
351 unsigned.flush()
352
Narayan Kamatha07bf042017-08-14 14:49:21 +0100353 if is_compressed:
354 uncompressed = tempfile.NamedTemporaryFile()
Tao Bao0c28d2d2017-12-24 10:37:38 -0800355 with gzip.open(unsigned.name, "rb") as in_file, \
356 open(uncompressed.name, "wb") as out_file:
Narayan Kamatha07bf042017-08-14 14:49:21 +0100357 shutil.copyfileobj(in_file, out_file)
358
359 # Finally, close the "unsigned" file (which is gzip compressed), and then
360 # replace it with the uncompressed version.
361 #
362 # TODO(narayan): All this nastiness can be avoided if python 3.2 is in use,
363 # we could just gzip / gunzip in-memory buffers instead.
364 unsigned.close()
365 unsigned = uncompressed
366
Doug Zongkereef39442009-04-02 12:14:19 -0700367 signed = tempfile.NamedTemporaryFile()
368
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800369 # For pre-N builds, don't upgrade to SHA-256 JAR signatures based on the APK's
370 # minSdkVersion to avoid increasing incremental OTA update sizes. If an APK
371 # didn't change, we don't want its signature to change due to the switch
372 # from SHA-1 to SHA-256.
373 # By default, APK signer chooses SHA-256 signatures if the APK's minSdkVersion
374 # is 18 or higher. For pre-N builds we disable this mechanism by pretending
375 # that the APK's minSdkVersion is 1.
376 # For N+ builds, we let APK signer rely on the APK's minSdkVersion to
377 # determine whether to use SHA-256.
378 min_api_level = None
379 if platform_api_level > 23:
380 # Let APK signer choose whether to use SHA-1 or SHA-256, based on the APK's
381 # minSdkVersion attribute
382 min_api_level = None
383 else:
384 # Force APK signer to use SHA-1
385 min_api_level = 1
386
387 common.SignFile(unsigned.name, signed.name, keyname, pw,
Tao Bao0c28d2d2017-12-24 10:37:38 -0800388 min_api_level=min_api_level,
389 codename_to_api_level_map=codename_to_api_level_map)
Doug Zongkereef39442009-04-02 12:14:19 -0700390
Tao Bao0c28d2d2017-12-24 10:37:38 -0800391 data = None
Narayan Kamatha07bf042017-08-14 14:49:21 +0100392 if is_compressed:
393 # Recompress the file after it has been signed.
394 compressed = tempfile.NamedTemporaryFile()
Tao Bao0c28d2d2017-12-24 10:37:38 -0800395 with open(signed.name, "rb") as in_file, \
396 gzip.open(compressed.name, "wb") as out_file:
Narayan Kamatha07bf042017-08-14 14:49:21 +0100397 shutil.copyfileobj(in_file, out_file)
398
399 data = compressed.read()
400 compressed.close()
401 else:
402 data = signed.read()
403
Doug Zongkereef39442009-04-02 12:14:19 -0700404 unsigned.close()
405 signed.close()
406
407 return data
408
409
Doug Zongker412c02f2014-02-13 10:58:24 -0800410def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -0700411 apk_keys, apex_keys, key_passwords,
412 platform_api_level, codename_to_api_level_map,
Narayan Kamatha07bf042017-08-14 14:49:21 +0100413 compressed_extension):
Tao Bao93c2a012018-06-19 12:19:35 -0700414 # maxsize measures the maximum filename length, including the ones to be
415 # skipped.
Tao Bao0c28d2d2017-12-24 10:37:38 -0800416 maxsize = max(
417 [len(os.path.basename(i.filename)) for i in input_tf_zip.infolist()
Tao Bao93c2a012018-06-19 12:19:35 -0700418 if GetApkFileInfo(i.filename, compressed_extension, [])[0]])
Tao Baoa80ed222016-06-16 14:41:24 -0700419 system_root_image = misc_info.get("system_root_image") == "true"
Doug Zongker412c02f2014-02-13 10:58:24 -0800420
Doug Zongkereef39442009-04-02 12:14:19 -0700421 for info in input_tf_zip.infolist():
Tao Bao11f955c2018-06-19 12:19:35 -0700422 filename = info.filename
423 if filename.startswith("IMAGES/"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700424 continue
Doug Zongker3c84f562014-07-31 11:06:30 -0700425
Tao Bao04808502019-07-25 23:11:41 -0700426 # Skip OTA-specific images (e.g. split super images), which will be
427 # re-generated during signing.
Tao Bao33bf2682019-01-11 12:37:35 -0800428 if filename.startswith("OTA/") and filename.endswith(".img"):
429 continue
430
Tao Bao11f955c2018-06-19 12:19:35 -0700431 data = input_tf_zip.read(filename)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700432 out_info = copy.copy(info)
Tao Bao93c2a012018-06-19 12:19:35 -0700433 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
434 filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
435
436 if is_apk and should_be_skipped:
437 # Copy skipped APKs verbatim.
438 print(
439 "NOT signing: %s\n"
440 " (skipped due to matching prefix)" % (filename,))
441 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker412c02f2014-02-13 10:58:24 -0800442
Tao Baof2cffbd2015-07-22 12:33:18 -0700443 # Sign APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700444 elif is_apk:
Tao Bao11f955c2018-06-19 12:19:35 -0700445 name = os.path.basename(filename)
Narayan Kamatha07bf042017-08-14 14:49:21 +0100446 if is_compressed:
447 name = name[:-len(compressed_extension)]
448
Tao Baoaa7e9932019-03-15 09:37:01 -0700449 key = apk_keys[name]
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800450 if key not in common.SPECIAL_CERT_STRINGS:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800451 print(" signing: %-*s (%s)" % (maxsize, name, key))
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800452 signed_data = SignApk(data, key, key_passwords[key], platform_api_level,
Tao Bao0c28d2d2017-12-24 10:37:38 -0800453 codename_to_api_level_map, is_compressed)
Tao Bao2ed665a2015-04-01 11:21:55 -0700454 common.ZipWriteStr(output_tf_zip, out_info, signed_data)
Doug Zongkereef39442009-04-02 12:14:19 -0700455 else:
456 # an APK we're not supposed to sign.
Tao Bao93c2a012018-06-19 12:19:35 -0700457 print(
458 "NOT signing: %s\n"
459 " (skipped due to special cert string)" % (name,))
Tao Bao2ed665a2015-04-01 11:21:55 -0700460 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoa80ed222016-06-16 14:41:24 -0700461
Tao Baoaa7e9932019-03-15 09:37:01 -0700462 # Sign bundled APEX files.
463 elif filename.startswith("SYSTEM/apex") and filename.endswith(".apex"):
464 name = os.path.basename(filename)
465 payload_key, container_key = apex_keys[name]
466
Tao Baoe1343992019-03-19 12:24:03 -0700467 # We've asserted not having a case with only one of them PRESIGNED.
468 if (payload_key not in common.SPECIAL_CERT_STRINGS and
469 container_key not in common.SPECIAL_CERT_STRINGS):
470 print(" signing: %-*s container (%s)" % (
471 maxsize, name, container_key))
472 print(" : %-*s payload (%s)" % (
473 maxsize, name, payload_key))
Tao Baoaa7e9932019-03-15 09:37:01 -0700474
Tao Baoe7354ba2019-05-09 16:54:15 -0700475 signed_apex = apex_utils.SignApex(
Tao Bao1ac886e2019-06-26 11:58:22 -0700476 misc_info['avb_avbtool'],
Tao Baoe1343992019-03-19 12:24:03 -0700477 data,
478 payload_key,
479 container_key,
480 key_passwords[container_key],
481 codename_to_api_level_map,
Tao Bao448004a2019-09-19 07:55:02 -0700482 no_hashtree=True,
483 signing_args=OPTIONS.avb_extra_args.get('apex'))
Tao Baoe1343992019-03-19 12:24:03 -0700484 common.ZipWrite(output_tf_zip, signed_apex, filename)
Tao Baoaa7e9932019-03-15 09:37:01 -0700485
Tao Baoe1343992019-03-19 12:24:03 -0700486 else:
487 print(
488 "NOT signing: %s\n"
489 " (skipped due to special cert string)" % (name,))
490 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoaa7e9932019-03-15 09:37:01 -0700491
492 # AVB public keys for the installed APEXes, which will be updated later.
493 elif (os.path.dirname(filename) == 'SYSTEM/etc/security/apex' and
494 filename != 'SYSTEM/etc/security/apex/'):
495 continue
496
Tao Baoa80ed222016-06-16 14:41:24 -0700497 # System properties.
Tao Bao338c1b72019-06-21 09:38:24 -0700498 elif filename in (
499 "SYSTEM/build.prop",
500
501 "VENDOR/build.prop",
502 "SYSTEM/vendor/build.prop",
503
504 "ODM/etc/build.prop",
505 "VENDOR/odm/etc/build.prop",
506
507 "PRODUCT/build.prop",
508 "SYSTEM/product/build.prop",
509
Justin Yun6151e3f2019-06-25 15:58:13 +0900510 "SYSTEM_EXT/build.prop",
511 "SYSTEM/system_ext/build.prop",
Tao Bao338c1b72019-06-21 09:38:24 -0700512
513 "SYSTEM/etc/prop.default",
514 "BOOT/RAMDISK/prop.default",
515 "RECOVERY/RAMDISK/prop.default",
516
517 # ROOT/default.prop is a legacy path, but may still exist for upgrading
518 # devices that don't support `property_overrides_split_enabled`.
519 "ROOT/default.prop",
520
521 # RECOVERY/RAMDISK/default.prop is a legacy path, but will always exist
522 # as a symlink in the current code. So it's a no-op here. Keeping the
523 # path here for clarity.
524 "RECOVERY/RAMDISK/default.prop"):
Tao Bao11f955c2018-06-19 12:19:35 -0700525 print("Rewriting %s:" % (filename,))
Hung-ying Tyan7eb6a922017-05-01 21:56:26 +0800526 if stat.S_ISLNK(info.external_attr >> 16):
527 new_data = data
528 else:
Tao Baoa3705452019-06-24 15:33:41 -0700529 new_data = RewriteProps(data.decode())
Tao Bao2ed665a2015-04-01 11:21:55 -0700530 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700531
Tao Bao66472632017-12-04 17:16:36 -0800532 # Replace the certs in *mac_permissions.xml (there could be multiple, such
533 # as {system,vendor}/etc/selinux/{plat,nonplat}_mac_permissions.xml).
Tao Bao11f955c2018-06-19 12:19:35 -0700534 elif filename.endswith("mac_permissions.xml"):
535 print("Rewriting %s with new keys." % (filename,))
Tao Baoa3705452019-06-24 15:33:41 -0700536 new_data = ReplaceCerts(data.decode())
Tao Bao2ed665a2015-04-01 11:21:55 -0700537 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700538
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700539 # Ask add_img_to_target_files to rebuild the recovery patch if needed.
Tao Bao11f955c2018-06-19 12:19:35 -0700540 elif filename in ("SYSTEM/recovery-from-boot.p",
541 "SYSTEM/etc/recovery.img",
542 "SYSTEM/bin/install-recovery.sh"):
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700543 OPTIONS.rebuild_recovery = True
Tao Baoa80ed222016-06-16 14:41:24 -0700544
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700545 # Don't copy OTA certs if we're replacing them.
Tao Bao696bb332018-08-17 16:27:01 -0700546 elif (
547 OPTIONS.replace_ota_keys and
548 filename in (
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700549 "BOOT/RAMDISK/system/etc/security/otacerts.zip",
Tao Bao696bb332018-08-17 16:27:01 -0700550 "BOOT/RAMDISK/system/etc/update_engine/update-payload-key.pub.pem",
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700551 "RECOVERY/RAMDISK/system/etc/security/otacerts.zip",
Tao Bao696bb332018-08-17 16:27:01 -0700552 "SYSTEM/etc/security/otacerts.zip",
553 "SYSTEM/etc/update_engine/update-payload-key.pub.pem")):
Doug Zongker412c02f2014-02-13 10:58:24 -0800554 pass
Tao Baoa80ed222016-06-16 14:41:24 -0700555
Tao Bao46a59992017-06-05 11:55:16 -0700556 # Skip META/misc_info.txt since we will write back the new values later.
Tao Bao11f955c2018-06-19 12:19:35 -0700557 elif filename == "META/misc_info.txt":
Geremy Condraf19b3652014-07-29 17:54:54 -0700558 pass
Tao Bao8adcfd12016-06-17 17:01:22 -0700559
560 # Skip verity public key if we will replace it.
Michael Runge947894f2014-10-14 20:58:38 -0700561 elif (OPTIONS.replace_verity_public_key and
Tao Bao11f955c2018-06-19 12:19:35 -0700562 filename in ("BOOT/RAMDISK/verity_key",
563 "ROOT/verity_key")):
Geremy Condraf19b3652014-07-29 17:54:54 -0700564 pass
Tao Baoa80ed222016-06-16 14:41:24 -0700565
Tao Bao8adcfd12016-06-17 17:01:22 -0700566 # Skip verity keyid (for system_root_image use) if we will replace it.
Tao Bao11f955c2018-06-19 12:19:35 -0700567 elif OPTIONS.replace_verity_keyid and filename == "BOOT/cmdline":
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700568 pass
569
Tianjie Xu4f099002016-08-11 18:04:27 -0700570 # Skip the care_map as we will regenerate the system/vendor images.
Tianjie Xu4c05f4a2018-09-14 16:24:41 -0700571 elif filename == "META/care_map.pb" or filename == "META/care_map.txt":
Tianjie Xu4f099002016-08-11 18:04:27 -0700572 pass
573
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800574 # Updates system_other.avbpubkey in /product/etc/.
575 elif filename in (
576 "PRODUCT/etc/security/avb/system_other.avbpubkey",
577 "SYSTEM/product/etc/security/avb/system_other.avbpubkey"):
578 # Only update system_other's public key, if the corresponding signing
579 # key is specified via --avb_system_other_key.
580 signing_key = OPTIONS.avb_keys.get("system_other")
581 if signing_key:
Tao Bao1ac886e2019-06-26 11:58:22 -0700582 public_key = common.ExtractAvbPublicKey(
583 misc_info['avb_avbtool'], signing_key)
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800584 print(" Rewriting AVB public key of system_other in /product")
585 common.ZipWrite(output_tf_zip, public_key, filename)
586
Bowgo Tsai78369eb2019-04-23 12:28:44 +0800587 # Should NOT sign boot-debug.img.
588 elif filename in (
589 "BOOT/RAMDISK/force_debuggable",
590 "RECOVERY/RAMDISK/force_debuggable"
591 "RECOVERY/RAMDISK/first_stage_ramdisk/force_debuggable"):
592 raise common.ExternalError("debuggable boot.img cannot be signed")
593
Tao Baoa80ed222016-06-16 14:41:24 -0700594 # A non-APK file; copy it verbatim.
Doug Zongkereef39442009-04-02 12:14:19 -0700595 else:
Tao Bao2ed665a2015-04-01 11:21:55 -0700596 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700597
Doug Zongker412c02f2014-02-13 10:58:24 -0800598 if OPTIONS.replace_ota_keys:
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700599 ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info)
Doug Zongker412c02f2014-02-13 10:58:24 -0800600
Tao Bao46a59992017-06-05 11:55:16 -0700601 # Replace the keyid string in misc_info dict.
Tao Bao8adcfd12016-06-17 17:01:22 -0700602 if OPTIONS.replace_verity_private_key:
Tao Bao46a59992017-06-05 11:55:16 -0700603 ReplaceVerityPrivateKey(misc_info, OPTIONS.replace_verity_private_key[1])
Tao Bao8adcfd12016-06-17 17:01:22 -0700604
605 if OPTIONS.replace_verity_public_key:
Tao Baoc9981932019-09-16 12:10:43 -0700606 # Replace the one in root dir in system.img.
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700607 ReplaceVerityPublicKey(
Tao Baoc9981932019-09-16 12:10:43 -0700608 output_tf_zip, 'ROOT/verity_key', OPTIONS.replace_verity_public_key[1])
609
610 if not system_root_image:
611 # Additionally replace the copy in ramdisk if not using system-as-root.
612 ReplaceVerityPublicKey(
613 output_tf_zip,
614 'BOOT/RAMDISK/verity_key',
615 OPTIONS.replace_verity_public_key[1])
Tao Bao8adcfd12016-06-17 17:01:22 -0700616
617 # Replace the keyid string in BOOT/cmdline.
618 if OPTIONS.replace_verity_keyid:
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700619 ReplaceVerityKeyId(input_tf_zip, output_tf_zip,
620 OPTIONS.replace_verity_keyid[1])
Doug Zongker412c02f2014-02-13 10:58:24 -0800621
Tao Bao639118f2017-06-19 15:48:02 -0700622 # Replace the AVB signing keys, if any.
623 ReplaceAvbSigningKeys(misc_info)
624
Tao Bao46a59992017-06-05 11:55:16 -0700625 # Write back misc_info with the latest values.
626 ReplaceMiscInfoTxt(input_tf_zip, output_tf_zip, misc_info)
627
Doug Zongker8e931bf2009-04-06 15:21:45 -0700628
Robert Craig817c5742013-04-19 10:59:22 -0400629def ReplaceCerts(data):
Tao Bao66472632017-12-04 17:16:36 -0800630 """Replaces all the occurences of X.509 certs with the new ones.
Robert Craig817c5742013-04-19 10:59:22 -0400631
Tao Bao66472632017-12-04 17:16:36 -0800632 The mapping info is read from OPTIONS.key_map. Non-existent certificate will
633 be skipped. After the replacement, it additionally checks for duplicate
634 entries, which would otherwise fail the policy loading code in
635 frameworks/base/services/core/java/com/android/server/pm/SELinuxMMAC.java.
636
637 Args:
638 data: Input string that contains a set of X.509 certs.
639
640 Returns:
641 A string after the replacement.
642
643 Raises:
644 AssertionError: On finding duplicate entries.
645 """
Tao Baoa3705452019-06-24 15:33:41 -0700646 for old, new in OPTIONS.key_map.items():
Tao Bao66472632017-12-04 17:16:36 -0800647 if OPTIONS.verbose:
648 print(" Replacing %s.x509.pem with %s.x509.pem" % (old, new))
649
650 try:
651 with open(old + ".x509.pem") as old_fp:
652 old_cert16 = base64.b16encode(
Tao Baoa3705452019-06-24 15:33:41 -0700653 common.ParseCertificate(old_fp.read())).decode().lower()
Tao Bao66472632017-12-04 17:16:36 -0800654 with open(new + ".x509.pem") as new_fp:
655 new_cert16 = base64.b16encode(
Tao Baoa3705452019-06-24 15:33:41 -0700656 common.ParseCertificate(new_fp.read())).decode().lower()
Tao Bao66472632017-12-04 17:16:36 -0800657 except IOError as e:
658 if OPTIONS.verbose or e.errno != errno.ENOENT:
659 print(" Error accessing %s: %s.\nSkip replacing %s.x509.pem with "
660 "%s.x509.pem." % (e.filename, e.strerror, old, new))
661 continue
662
663 # Only match entire certs.
664 pattern = "\\b" + old_cert16 + "\\b"
665 (data, num) = re.subn(pattern, new_cert16, data, flags=re.IGNORECASE)
666
667 if OPTIONS.verbose:
668 print(" Replaced %d occurence(s) of %s.x509.pem with %s.x509.pem" % (
669 num, old, new))
670
671 # Verify that there're no duplicate entries after the replacement. Note that
672 # it's only checking entries with global seinfo at the moment (i.e. ignoring
673 # the ones with inner packages). (Bug: 69479366)
674 root = ElementTree.fromstring(data)
675 signatures = [signer.attrib['signature'] for signer in root.findall('signer')]
676 assert len(signatures) == len(set(signatures)), \
677 "Found duplicate entries after cert replacement: {}".format(data)
Robert Craig817c5742013-04-19 10:59:22 -0400678
679 return data
680
681
Doug Zongkerc09abc82010-01-11 13:09:15 -0800682def EditTags(tags):
Tao Baoa7054ee2017-12-08 14:42:16 -0800683 """Applies the edits to the tag string as specified in OPTIONS.tag_changes.
684
685 Args:
686 tags: The input string that contains comma-separated tags.
687
688 Returns:
689 The updated tags (comma-separated and sorted).
690 """
Doug Zongkerc09abc82010-01-11 13:09:15 -0800691 tags = set(tags.split(","))
692 for ch in OPTIONS.tag_changes:
693 if ch[0] == "-":
694 tags.discard(ch[1:])
695 elif ch[0] == "+":
696 tags.add(ch[1:])
697 return ",".join(sorted(tags))
698
699
Tao Baoa7054ee2017-12-08 14:42:16 -0800700def RewriteProps(data):
701 """Rewrites the system properties in the given string.
702
703 Each property is expected in 'key=value' format. The properties that contain
704 build tags (i.e. test-keys, dev-keys) will be updated accordingly by calling
705 EditTags().
706
707 Args:
708 data: Input string, separated by newlines.
709
710 Returns:
711 The string with modified properties.
712 """
Doug Zongker17aa9442009-04-17 10:15:58 -0700713 output = []
714 for line in data.split("\n"):
715 line = line.strip()
716 original_line = line
Michael Rungedc2661a2014-06-03 14:43:11 -0700717 if line and line[0] != '#' and "=" in line:
Doug Zongker17aa9442009-04-17 10:15:58 -0700718 key, value = line.split("=", 1)
Magnus Strandh234f4b42019-05-01 23:09:30 +0200719 if (key.startswith("ro.") and
720 key.endswith((".build.fingerprint", ".build.thumbprint"))):
Doug Zongkerc09abc82010-01-11 13:09:15 -0800721 pieces = value.split("/")
722 pieces[-1] = EditTags(pieces[-1])
723 value = "/".join(pieces)
Tao Baocb7ff772015-09-11 15:27:56 -0700724 elif key == "ro.bootimage.build.fingerprint":
725 pieces = value.split("/")
726 pieces[-1] = EditTags(pieces[-1])
727 value = "/".join(pieces)
Doug Zongker17aa9442009-04-17 10:15:58 -0700728 elif key == "ro.build.description":
Doug Zongkerc09abc82010-01-11 13:09:15 -0800729 pieces = value.split(" ")
Doug Zongker17aa9442009-04-17 10:15:58 -0700730 assert len(pieces) == 5
Doug Zongkerc09abc82010-01-11 13:09:15 -0800731 pieces[-1] = EditTags(pieces[-1])
732 value = " ".join(pieces)
Magnus Strandh234f4b42019-05-01 23:09:30 +0200733 elif key.startswith("ro.") and key.endswith(".build.tags"):
Doug Zongkerc09abc82010-01-11 13:09:15 -0800734 value = EditTags(value)
Doug Zongkera8608a72013-07-23 11:51:04 -0700735 elif key == "ro.build.display.id":
736 # change, eg, "JWR66N dev-keys" to "JWR66N"
737 value = value.split()
Michael Rungedc2661a2014-06-03 14:43:11 -0700738 if len(value) > 1 and value[-1].endswith("-keys"):
Andrew Boie73d5abb2013-12-11 12:42:03 -0800739 value.pop()
740 value = " ".join(value)
Doug Zongkerc09abc82010-01-11 13:09:15 -0800741 line = key + "=" + value
Doug Zongker17aa9442009-04-17 10:15:58 -0700742 if line != original_line:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800743 print(" replace: ", original_line)
744 print(" with: ", line)
Doug Zongker17aa9442009-04-17 10:15:58 -0700745 output.append(line)
746 return "\n".join(output) + "\n"
747
748
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700749def WriteOtacerts(output_zip, filename, keys):
750 """Constructs a zipfile from given keys; and writes it to output_zip.
751
752 Args:
753 output_zip: The output target_files zip.
754 filename: The archive name in the output zip.
755 keys: A list of public keys to use during OTA package verification.
756 """
Tao Baobb733882019-07-24 23:31:19 -0700757 temp_file = io.BytesIO()
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700758 certs_zip = zipfile.ZipFile(temp_file, "w")
759 for k in keys:
760 common.ZipWrite(certs_zip, k)
761 common.ZipClose(certs_zip)
762 common.ZipWriteStr(output_zip, filename, temp_file.getvalue())
763
764
Doug Zongker831840e2011-09-22 10:28:04 -0700765def ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info):
Doug Zongker8e931bf2009-04-06 15:21:45 -0700766 try:
767 keylist = input_tf_zip.read("META/otakeys.txt").split()
768 except KeyError:
T.R. Fullharta28acc62013-03-18 10:31:26 -0700769 raise common.ExternalError("can't read META/otakeys.txt from input")
Doug Zongker8e931bf2009-04-06 15:21:45 -0700770
Tao Baof718f902017-11-09 10:10:10 -0800771 extra_recovery_keys = misc_info.get("extra_recovery_keys")
Doug Zongkere121d6a2011-02-01 14:13:52 -0800772 if extra_recovery_keys:
773 extra_recovery_keys = [OPTIONS.key_map.get(k, k) + ".x509.pem"
774 for k in extra_recovery_keys.split()]
775 if extra_recovery_keys:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800776 print("extra recovery-only key(s): " + ", ".join(extra_recovery_keys))
Doug Zongkere121d6a2011-02-01 14:13:52 -0800777 else:
778 extra_recovery_keys = []
779
Doug Zongker8e931bf2009-04-06 15:21:45 -0700780 mapped_keys = []
781 for k in keylist:
782 m = re.match(r"^(.*)\.x509\.pem$", k)
783 if not m:
Doug Zongker412c02f2014-02-13 10:58:24 -0800784 raise common.ExternalError(
785 "can't parse \"%s\" from META/otakeys.txt" % (k,))
Doug Zongker8e931bf2009-04-06 15:21:45 -0700786 k = m.group(1)
787 mapped_keys.append(OPTIONS.key_map.get(k, k) + ".x509.pem")
788
Doug Zongkere05628c2009-08-20 17:38:42 -0700789 if mapped_keys:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800790 print("using:\n ", "\n ".join(mapped_keys))
791 print("for OTA package verification")
Doug Zongkere05628c2009-08-20 17:38:42 -0700792 else:
Doug Zongker831840e2011-09-22 10:28:04 -0700793 devkey = misc_info.get("default_system_dev_certificate",
Dan Willemsen0ab1be62019-04-09 21:35:37 -0700794 "build/make/target/product/security/testkey")
Tao Baof718f902017-11-09 10:10:10 -0800795 mapped_devkey = OPTIONS.key_map.get(devkey, devkey)
796 if mapped_devkey != devkey:
797 misc_info["default_system_dev_certificate"] = mapped_devkey
798 mapped_keys.append(mapped_devkey + ".x509.pem")
Tao Baoa80ed222016-06-16 14:41:24 -0700799 print("META/otakeys.txt has no keys; using %s for OTA package"
800 " verification." % (mapped_keys[0],))
Doug Zongker8e931bf2009-04-06 15:21:45 -0700801
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700802 # recovery now uses the same x509.pem version of the keys.
Doug Zongkere121d6a2011-02-01 14:13:52 -0800803 # extra_recovery_keys are used only in recovery.
Tom Cherry2929cad2018-09-20 11:04:37 -0700804 if misc_info.get("recovery_as_boot") == "true":
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700805 recovery_keys_location = "BOOT/RAMDISK/system/etc/security/otacerts.zip"
Tao Baoa80ed222016-06-16 14:41:24 -0700806 else:
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700807 recovery_keys_location = "RECOVERY/RAMDISK/system/etc/security/otacerts.zip"
808
809 WriteOtacerts(output_tf_zip, recovery_keys_location,
810 mapped_keys + extra_recovery_keys)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700811
812 # SystemUpdateActivity uses the x509.pem version of the keys, but
813 # put into a zipfile system/etc/security/otacerts.zip.
Doug Zongkere121d6a2011-02-01 14:13:52 -0800814 # We DO NOT include the extra_recovery_keys (if any) here.
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700815 WriteOtacerts(output_tf_zip, "SYSTEM/etc/security/otacerts.zip", mapped_keys)
Doug Zongkereef39442009-04-02 12:14:19 -0700816
Tao Baoa80ed222016-06-16 14:41:24 -0700817 # For A/B devices, update the payload verification key.
818 if misc_info.get("ab_update") == "true":
819 # Unlike otacerts.zip that may contain multiple keys, we can only specify
820 # ONE payload verification key.
821 if len(mapped_keys) > 1:
822 print("\n WARNING: Found more than one OTA keys; Using the first one"
823 " as payload verification key.\n\n")
824
Tao Bao0c28d2d2017-12-24 10:37:38 -0800825 print("Using %s for payload verification." % (mapped_keys[0],))
Tao Bao04e1f012018-02-04 12:13:35 -0800826 pubkey = common.ExtractPublicKey(mapped_keys[0])
Tao Bao13b69622016-07-06 15:28:59 -0700827 common.ZipWriteStr(
Tao Baoa80ed222016-06-16 14:41:24 -0700828 output_tf_zip,
Tao Bao13b69622016-07-06 15:28:59 -0700829 "SYSTEM/etc/update_engine/update-payload-key.pub.pem",
830 pubkey)
Alex Deymob3e8ce62016-08-04 16:06:12 -0700831 common.ZipWriteStr(
832 output_tf_zip,
Tao Bao696bb332018-08-17 16:27:01 -0700833 "BOOT/RAMDISK/system/etc/update_engine/update-payload-key.pub.pem",
Alex Deymob3e8ce62016-08-04 16:06:12 -0700834 pubkey)
Tao Baoa80ed222016-06-16 14:41:24 -0700835
Tao Bao8adcfd12016-06-17 17:01:22 -0700836
Tao Bao0c28d2d2017-12-24 10:37:38 -0800837def ReplaceVerityPublicKey(output_zip, filename, key_path):
838 """Replaces the verity public key at the given path in the given zip.
839
840 Args:
841 output_zip: The output target_files zip.
842 filename: The archive name in the output zip.
843 key_path: The path to the public key.
844 """
845 print("Replacing verity public key with %s" % (key_path,))
846 common.ZipWrite(output_zip, key_path, arcname=filename)
Geremy Condraf19b3652014-07-29 17:54:54 -0700847
Tao Bao8adcfd12016-06-17 17:01:22 -0700848
Tao Bao46a59992017-06-05 11:55:16 -0700849def ReplaceVerityPrivateKey(misc_info, key_path):
Tao Bao0c28d2d2017-12-24 10:37:38 -0800850 """Replaces the verity private key in misc_info dict.
851
852 Args:
853 misc_info: The info dict.
854 key_path: The path to the private key in PKCS#8 format.
855 """
856 print("Replacing verity private key with %s" % (key_path,))
Andrew Boied083f0b2014-09-15 16:01:07 -0700857 misc_info["verity_key"] = key_path
Doug Zongkereef39442009-04-02 12:14:19 -0700858
Tao Bao8adcfd12016-06-17 17:01:22 -0700859
Tao Baoe838d142017-12-23 23:44:48 -0800860def ReplaceVerityKeyId(input_zip, output_zip, key_path):
861 """Replaces the veritykeyid parameter in BOOT/cmdline.
862
863 Args:
864 input_zip: The input target_files zip, which should be already open.
865 output_zip: The output target_files zip, which should be already open and
866 writable.
867 key_path: The path to the PEM encoded X.509 certificate.
868 """
Tao Baoa3705452019-06-24 15:33:41 -0700869 in_cmdline = input_zip.read("BOOT/cmdline").decode()
Tao Baoe838d142017-12-23 23:44:48 -0800870 # Copy in_cmdline to output_zip if veritykeyid is not present.
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700871 if "veritykeyid" not in in_cmdline:
Tao Baoe838d142017-12-23 23:44:48 -0800872 common.ZipWriteStr(output_zip, "BOOT/cmdline", in_cmdline)
873 return
874
Tao Bao0c28d2d2017-12-24 10:37:38 -0800875 out_buffer = []
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700876 for param in in_cmdline.split():
Tao Baoe838d142017-12-23 23:44:48 -0800877 if "veritykeyid" not in param:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800878 out_buffer.append(param)
Tao Baoe838d142017-12-23 23:44:48 -0800879 continue
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700880
Tao Baoe838d142017-12-23 23:44:48 -0800881 # Extract keyid using openssl command.
882 p = common.Run(["openssl", "x509", "-in", key_path, "-text"],
Tao Baode1d4792018-02-20 10:05:46 -0800883 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
Tao Baoe838d142017-12-23 23:44:48 -0800884 keyid, stderr = p.communicate()
885 assert p.returncode == 0, "Failed to dump certificate: {}".format(stderr)
886 keyid = re.search(
887 r'keyid:([0-9a-fA-F:]*)', keyid).group(1).replace(':', '').lower()
888 print("Replacing verity keyid with {}".format(keyid))
889 out_buffer.append("veritykeyid=id:%s" % (keyid,))
890
891 out_cmdline = ' '.join(out_buffer).strip() + '\n'
892 common.ZipWriteStr(output_zip, "BOOT/cmdline", out_cmdline)
Tao Bao46a59992017-06-05 11:55:16 -0700893
894
895def ReplaceMiscInfoTxt(input_zip, output_zip, misc_info):
896 """Replaces META/misc_info.txt.
897
898 Only writes back the ones in the original META/misc_info.txt. Because the
899 current in-memory dict contains additional items computed at runtime.
900 """
901 misc_info_old = common.LoadDictionaryFromLines(
Tao Baoa3705452019-06-24 15:33:41 -0700902 input_zip.read('META/misc_info.txt').decode().split('\n'))
Tao Bao46a59992017-06-05 11:55:16 -0700903 items = []
904 for key in sorted(misc_info):
905 if key in misc_info_old:
906 items.append('%s=%s' % (key, misc_info[key]))
907 common.ZipWriteStr(output_zip, "META/misc_info.txt", '\n'.join(items))
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700908
Tao Bao8adcfd12016-06-17 17:01:22 -0700909
Tao Bao639118f2017-06-19 15:48:02 -0700910def ReplaceAvbSigningKeys(misc_info):
911 """Replaces the AVB signing keys."""
912
913 AVB_FOOTER_ARGS_BY_PARTITION = {
Tao Bao0c28d2d2017-12-24 10:37:38 -0800914 'boot' : 'avb_boot_add_hash_footer_args',
915 'dtbo' : 'avb_dtbo_add_hash_footer_args',
916 'recovery' : 'avb_recovery_add_hash_footer_args',
917 'system' : 'avb_system_add_hashtree_footer_args',
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800918 'system_other' : 'avb_system_other_add_hashtree_footer_args',
Tao Bao0c28d2d2017-12-24 10:37:38 -0800919 'vendor' : 'avb_vendor_add_hashtree_footer_args',
920 'vbmeta' : 'avb_vbmeta_args',
Tao Baod6085d62019-05-06 12:55:42 -0700921 'vbmeta_system' : 'avb_vbmeta_system_args',
922 'vbmeta_vendor' : 'avb_vbmeta_vendor_args',
Tao Bao639118f2017-06-19 15:48:02 -0700923 }
924
925 def ReplaceAvbPartitionSigningKey(partition):
926 key = OPTIONS.avb_keys.get(partition)
927 if not key:
928 return
929
930 algorithm = OPTIONS.avb_algorithms.get(partition)
931 assert algorithm, 'Missing AVB signing algorithm for %s' % (partition,)
932
Tao Bao0c28d2d2017-12-24 10:37:38 -0800933 print('Replacing AVB signing key for %s with "%s" (%s)' % (
934 partition, key, algorithm))
Tao Bao639118f2017-06-19 15:48:02 -0700935 misc_info['avb_' + partition + '_algorithm'] = algorithm
936 misc_info['avb_' + partition + '_key_path'] = key
937
938 extra_args = OPTIONS.avb_extra_args.get(partition)
939 if extra_args:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800940 print('Setting extra AVB signing args for %s to "%s"' % (
941 partition, extra_args))
Tao Bao639118f2017-06-19 15:48:02 -0700942 args_key = AVB_FOOTER_ARGS_BY_PARTITION[partition]
943 misc_info[args_key] = (misc_info.get(args_key, '') + ' ' + extra_args)
944
945 for partition in AVB_FOOTER_ARGS_BY_PARTITION:
946 ReplaceAvbPartitionSigningKey(partition)
947
948
Doug Zongker831840e2011-09-22 10:28:04 -0700949def BuildKeyMap(misc_info, key_mapping_options):
950 for s, d in key_mapping_options:
951 if s is None: # -d option
952 devkey = misc_info.get("default_system_dev_certificate",
Dan Willemsen0ab1be62019-04-09 21:35:37 -0700953 "build/make/target/product/security/testkey")
Doug Zongker831840e2011-09-22 10:28:04 -0700954 devkeydir = os.path.dirname(devkey)
955
956 OPTIONS.key_map.update({
957 devkeydir + "/testkey": d + "/releasekey",
958 devkeydir + "/devkey": d + "/releasekey",
959 devkeydir + "/media": d + "/media",
960 devkeydir + "/shared": d + "/shared",
961 devkeydir + "/platform": d + "/platform",
962 })
963 else:
964 OPTIONS.key_map[s] = d
965
966
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800967def GetApiLevelAndCodename(input_tf_zip):
Tao Baoa3705452019-06-24 15:33:41 -0700968 data = input_tf_zip.read("SYSTEM/build.prop").decode()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800969 api_level = None
970 codename = None
971 for line in data.split("\n"):
972 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800973 if line and line[0] != '#' and "=" in line:
974 key, value = line.split("=", 1)
975 key = key.strip()
976 if key == "ro.build.version.sdk":
977 api_level = int(value.strip())
978 elif key == "ro.build.version.codename":
979 codename = value.strip()
980
981 if api_level is None:
982 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
983 if codename is None:
984 raise ValueError("No ro.build.version.codename in SYSTEM/build.prop")
985
986 return (api_level, codename)
987
988
989def GetCodenameToApiLevelMap(input_tf_zip):
Tao Baoa3705452019-06-24 15:33:41 -0700990 data = input_tf_zip.read("SYSTEM/build.prop").decode()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800991 api_level = None
992 codenames = None
993 for line in data.split("\n"):
994 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800995 if line and line[0] != '#' and "=" in line:
996 key, value = line.split("=", 1)
997 key = key.strip()
998 if key == "ro.build.version.sdk":
999 api_level = int(value.strip())
1000 elif key == "ro.build.version.all_codenames":
1001 codenames = value.strip().split(",")
1002
1003 if api_level is None:
1004 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
1005 if codenames is None:
1006 raise ValueError("No ro.build.version.all_codenames in SYSTEM/build.prop")
1007
Tao Baoa3705452019-06-24 15:33:41 -07001008 result = {}
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001009 for codename in codenames:
1010 codename = codename.strip()
Tao Baobadceb22019-03-15 09:33:43 -07001011 if codename:
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001012 result[codename] = api_level
1013 return result
1014
1015
Tao Baoaa7e9932019-03-15 09:37:01 -07001016def ReadApexKeysInfo(tf_zip):
1017 """Parses the APEX keys info from a given target-files zip.
1018
1019 Given a target-files ZipFile, parses the META/apexkeys.txt entry and returns a
1020 dict that contains the mapping from APEX names (e.g. com.android.tzdata) to a
1021 tuple of (payload_key, container_key).
1022
1023 Args:
1024 tf_zip: The input target_files ZipFile (already open).
1025
1026 Returns:
1027 (payload_key, container_key): payload_key contains the path to the payload
1028 signing key; container_key contains the path to the container signing
1029 key.
1030 """
1031 keys = {}
Tao Baoa3705452019-06-24 15:33:41 -07001032 for line in tf_zip.read('META/apexkeys.txt').decode().split('\n'):
Tao Baoaa7e9932019-03-15 09:37:01 -07001033 line = line.strip()
1034 if not line:
1035 continue
1036 matches = re.match(
1037 r'^name="(?P<NAME>.*)"\s+'
1038 r'public_key="(?P<PAYLOAD_PUBLIC_KEY>.*)"\s+'
1039 r'private_key="(?P<PAYLOAD_PRIVATE_KEY>.*)"\s+'
1040 r'container_certificate="(?P<CONTAINER_CERT>.*)"\s+'
1041 r'container_private_key="(?P<CONTAINER_PRIVATE_KEY>.*)"$',
1042 line)
1043 if not matches:
1044 continue
1045
1046 name = matches.group('NAME')
Tao Baoaa7e9932019-03-15 09:37:01 -07001047 payload_private_key = matches.group("PAYLOAD_PRIVATE_KEY")
1048
1049 def CompareKeys(pubkey, pubkey_suffix, privkey, privkey_suffix):
1050 pubkey_suffix_len = len(pubkey_suffix)
1051 privkey_suffix_len = len(privkey_suffix)
1052 return (pubkey.endswith(pubkey_suffix) and
1053 privkey.endswith(privkey_suffix) and
1054 pubkey[:-pubkey_suffix_len] == privkey[:-privkey_suffix_len])
1055
Tao Bao6d9e3da2019-03-26 12:59:25 -07001056 # Sanity check on the container key names, as we'll carry them without the
1057 # extensions. This doesn't apply to payload keys though, which we will use
1058 # full names only.
Tao Baoaa7e9932019-03-15 09:37:01 -07001059 container_cert = matches.group("CONTAINER_CERT")
1060 container_private_key = matches.group("CONTAINER_PRIVATE_KEY")
Tao Baof454c3a2019-04-24 23:53:42 -07001061 if container_cert == 'PRESIGNED' and container_private_key == 'PRESIGNED':
1062 container_key = 'PRESIGNED'
1063 elif CompareKeys(
Tao Baoaa7e9932019-03-15 09:37:01 -07001064 container_cert, OPTIONS.public_key_suffix,
1065 container_private_key, OPTIONS.private_key_suffix):
Tao Baof454c3a2019-04-24 23:53:42 -07001066 container_key = container_cert[:-len(OPTIONS.public_key_suffix)]
1067 else:
Tao Baoaa7e9932019-03-15 09:37:01 -07001068 raise ValueError("Failed to parse container keys: \n{}".format(line))
1069
Tao Baof454c3a2019-04-24 23:53:42 -07001070 keys[name] = (payload_private_key, container_key)
Tao Baoaa7e9932019-03-15 09:37:01 -07001071
1072 return keys
1073
1074
Doug Zongkereef39442009-04-02 12:14:19 -07001075def main(argv):
1076
Doug Zongker831840e2011-09-22 10:28:04 -07001077 key_mapping_options = []
1078
Doug Zongkereef39442009-04-02 12:14:19 -07001079 def option_handler(o, a):
Doug Zongker05d3dea2009-06-22 11:32:31 -07001080 if o in ("-e", "--extra_apks"):
Doug Zongkereef39442009-04-02 12:14:19 -07001081 names, key = a.split("=")
1082 names = names.split(",")
1083 for n in names:
1084 OPTIONS.extra_apks[n] = key
Tao Baoaa7e9932019-03-15 09:37:01 -07001085 elif o == "--extra_apex_payload_key":
1086 apex_name, key = a.split("=")
1087 OPTIONS.extra_apex_payload_keys[apex_name] = key
Tao Bao93c2a012018-06-19 12:19:35 -07001088 elif o == "--skip_apks_with_path_prefix":
1089 # Sanity check the prefix, which must be in all upper case.
1090 prefix = a.split('/')[0]
1091 if not prefix or prefix != prefix.upper():
1092 raise ValueError("Invalid path prefix '%s'" % (a,))
1093 OPTIONS.skip_apks_with_path_prefix.add(a)
Doug Zongkereef39442009-04-02 12:14:19 -07001094 elif o in ("-d", "--default_key_mappings"):
Doug Zongker831840e2011-09-22 10:28:04 -07001095 key_mapping_options.append((None, a))
Doug Zongkereef39442009-04-02 12:14:19 -07001096 elif o in ("-k", "--key_mapping"):
Doug Zongker831840e2011-09-22 10:28:04 -07001097 key_mapping_options.append(a.split("=", 1))
Doug Zongker8e931bf2009-04-06 15:21:45 -07001098 elif o in ("-o", "--replace_ota_keys"):
1099 OPTIONS.replace_ota_keys = True
Doug Zongkerae877012009-04-21 10:04:51 -07001100 elif o in ("-t", "--tag_changes"):
1101 new = []
1102 for i in a.split(","):
1103 i = i.strip()
1104 if not i or i[0] not in "-+":
1105 raise ValueError("Bad tag change '%s'" % (i,))
1106 new.append(i[0] + i[1:].strip())
1107 OPTIONS.tag_changes = tuple(new)
Geremy Condraf19b3652014-07-29 17:54:54 -07001108 elif o == "--replace_verity_public_key":
1109 OPTIONS.replace_verity_public_key = (True, a)
1110 elif o == "--replace_verity_private_key":
1111 OPTIONS.replace_verity_private_key = (True, a)
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001112 elif o == "--replace_verity_keyid":
1113 OPTIONS.replace_verity_keyid = (True, a)
Tao Bao639118f2017-06-19 15:48:02 -07001114 elif o == "--avb_vbmeta_key":
1115 OPTIONS.avb_keys['vbmeta'] = a
1116 elif o == "--avb_vbmeta_algorithm":
1117 OPTIONS.avb_algorithms['vbmeta'] = a
1118 elif o == "--avb_vbmeta_extra_args":
1119 OPTIONS.avb_extra_args['vbmeta'] = a
1120 elif o == "--avb_boot_key":
1121 OPTIONS.avb_keys['boot'] = a
1122 elif o == "--avb_boot_algorithm":
1123 OPTIONS.avb_algorithms['boot'] = a
1124 elif o == "--avb_boot_extra_args":
1125 OPTIONS.avb_extra_args['boot'] = a
1126 elif o == "--avb_dtbo_key":
1127 OPTIONS.avb_keys['dtbo'] = a
1128 elif o == "--avb_dtbo_algorithm":
1129 OPTIONS.avb_algorithms['dtbo'] = a
1130 elif o == "--avb_dtbo_extra_args":
1131 OPTIONS.avb_extra_args['dtbo'] = a
1132 elif o == "--avb_system_key":
1133 OPTIONS.avb_keys['system'] = a
1134 elif o == "--avb_system_algorithm":
1135 OPTIONS.avb_algorithms['system'] = a
1136 elif o == "--avb_system_extra_args":
1137 OPTIONS.avb_extra_args['system'] = a
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001138 elif o == "--avb_system_other_key":
1139 OPTIONS.avb_keys['system_other'] = a
1140 elif o == "--avb_system_other_algorithm":
1141 OPTIONS.avb_algorithms['system_other'] = a
1142 elif o == "--avb_system_other_extra_args":
1143 OPTIONS.avb_extra_args['system_other'] = a
Tao Bao639118f2017-06-19 15:48:02 -07001144 elif o == "--avb_vendor_key":
1145 OPTIONS.avb_keys['vendor'] = a
1146 elif o == "--avb_vendor_algorithm":
1147 OPTIONS.avb_algorithms['vendor'] = a
1148 elif o == "--avb_vendor_extra_args":
1149 OPTIONS.avb_extra_args['vendor'] = a
Tao Baod6085d62019-05-06 12:55:42 -07001150 elif o == "--avb_vbmeta_system_key":
1151 OPTIONS.avb_keys['vbmeta_system'] = a
1152 elif o == "--avb_vbmeta_system_algorithm":
1153 OPTIONS.avb_algorithms['vbmeta_system'] = a
1154 elif o == "--avb_vbmeta_system_extra_args":
1155 OPTIONS.avb_extra_args['vbmeta_system'] = a
1156 elif o == "--avb_vbmeta_vendor_key":
1157 OPTIONS.avb_keys['vbmeta_vendor'] = a
1158 elif o == "--avb_vbmeta_vendor_algorithm":
1159 OPTIONS.avb_algorithms['vbmeta_vendor'] = a
1160 elif o == "--avb_vbmeta_vendor_extra_args":
1161 OPTIONS.avb_extra_args['vbmeta_vendor'] = a
Tao Baoaa7e9932019-03-15 09:37:01 -07001162 elif o == "--avb_apex_extra_args":
1163 OPTIONS.avb_extra_args['apex'] = a
Doug Zongkereef39442009-04-02 12:14:19 -07001164 else:
1165 return False
1166 return True
1167
Tao Bao639118f2017-06-19 15:48:02 -07001168 args = common.ParseOptions(
1169 argv, __doc__,
1170 extra_opts="e:d:k:ot:",
1171 extra_long_opts=[
Tao Bao0c28d2d2017-12-24 10:37:38 -08001172 "extra_apks=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001173 "extra_apex_payload_key=",
Tao Bao93c2a012018-06-19 12:19:35 -07001174 "skip_apks_with_path_prefix=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001175 "default_key_mappings=",
1176 "key_mapping=",
1177 "replace_ota_keys",
1178 "tag_changes=",
1179 "replace_verity_public_key=",
1180 "replace_verity_private_key=",
1181 "replace_verity_keyid=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001182 "avb_apex_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001183 "avb_vbmeta_algorithm=",
1184 "avb_vbmeta_key=",
1185 "avb_vbmeta_extra_args=",
1186 "avb_boot_algorithm=",
1187 "avb_boot_key=",
1188 "avb_boot_extra_args=",
1189 "avb_dtbo_algorithm=",
1190 "avb_dtbo_key=",
1191 "avb_dtbo_extra_args=",
1192 "avb_system_algorithm=",
1193 "avb_system_key=",
1194 "avb_system_extra_args=",
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001195 "avb_system_other_algorithm=",
1196 "avb_system_other_key=",
1197 "avb_system_other_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001198 "avb_vendor_algorithm=",
1199 "avb_vendor_key=",
1200 "avb_vendor_extra_args=",
Tao Baod6085d62019-05-06 12:55:42 -07001201 "avb_vbmeta_system_algorithm=",
1202 "avb_vbmeta_system_key=",
1203 "avb_vbmeta_system_extra_args=",
1204 "avb_vbmeta_vendor_algorithm=",
1205 "avb_vbmeta_vendor_key=",
1206 "avb_vbmeta_vendor_extra_args=",
Tao Bao639118f2017-06-19 15:48:02 -07001207 ],
1208 extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001209
1210 if len(args) != 2:
1211 common.Usage(__doc__)
1212 sys.exit(1)
1213
Tao Baobadceb22019-03-15 09:33:43 -07001214 common.InitLogging()
1215
Doug Zongkereef39442009-04-02 12:14:19 -07001216 input_zip = zipfile.ZipFile(args[0], "r")
Tao Bao2b8f4892017-06-13 12:54:58 -07001217 output_zip = zipfile.ZipFile(args[1], "w",
1218 compression=zipfile.ZIP_DEFLATED,
1219 allowZip64=True)
Doug Zongkereef39442009-04-02 12:14:19 -07001220
Doug Zongker831840e2011-09-22 10:28:04 -07001221 misc_info = common.LoadInfoDict(input_zip)
1222
1223 BuildKeyMap(misc_info, key_mapping_options)
1224
Tao Baoaa7e9932019-03-15 09:37:01 -07001225 apk_keys_info, compressed_extension = common.ReadApkCerts(input_zip)
1226 apk_keys = GetApkCerts(apk_keys_info)
Doug Zongkereb338ef2009-05-20 16:50:49 -07001227
Tao Baoaa7e9932019-03-15 09:37:01 -07001228 apex_keys_info = ReadApexKeysInfo(input_zip)
1229 apex_keys = GetApexKeys(apex_keys_info, apk_keys)
1230
1231 CheckApkAndApexKeysAvailable(
1232 input_zip,
1233 set(apk_keys.keys()) | set(apex_keys.keys()),
Tao Baoe1343992019-03-19 12:24:03 -07001234 compressed_extension,
1235 apex_keys)
Tao Baoaa7e9932019-03-15 09:37:01 -07001236
1237 key_passwords = common.GetKeyPasswords(
1238 set(apk_keys.values()) | set(itertools.chain(*apex_keys.values())))
Tao Bao9aa4b9b2016-09-29 17:53:56 -07001239 platform_api_level, _ = GetApiLevelAndCodename(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001240 codename_to_api_level_map = GetCodenameToApiLevelMap(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001241
Doug Zongker412c02f2014-02-13 10:58:24 -08001242 ProcessTargetFiles(input_zip, output_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -07001243 apk_keys, apex_keys, key_passwords,
1244 platform_api_level, codename_to_api_level_map,
Narayan Kamatha07bf042017-08-14 14:49:21 +01001245 compressed_extension)
Doug Zongker8e931bf2009-04-06 15:21:45 -07001246
Tao Bao2ed665a2015-04-01 11:21:55 -07001247 common.ZipClose(input_zip)
1248 common.ZipClose(output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001249
Tianjie Xub48589a2016-08-03 19:21:52 -07001250 # Skip building userdata.img and cache.img when signing the target files.
Tianjie Xu616fbeb2017-05-23 14:51:02 -07001251 new_args = ["--is_signing"]
1252 # add_img_to_target_files builds the system image from scratch, so the
1253 # recovery patch is guaranteed to be regenerated there.
1254 if OPTIONS.rebuild_recovery:
1255 new_args.append("--rebuild_recovery")
1256 new_args.append(args[1])
Tianjie Xub48589a2016-08-03 19:21:52 -07001257 add_img_to_target_files.main(new_args)
Doug Zongker3c84f562014-07-31 11:06:30 -07001258
Tao Bao0c28d2d2017-12-24 10:37:38 -08001259 print("done.")
Doug Zongkereef39442009-04-02 12:14:19 -07001260
1261
1262if __name__ == '__main__':
1263 try:
1264 main(sys.argv[1:])
Tao Bao0c28d2d2017-12-24 10:37:38 -08001265 except common.ExternalError as e:
1266 print("\n ERROR: %s\n" % (e,))
Doug Zongkereef39442009-04-02 12:14:19 -07001267 sys.exit(1)
Tao Bao639118f2017-06-19 15:48:02 -07001268 finally:
1269 common.Cleanup()