blob: 7eee59a59509852793faa1e00a3aedd8a6dcbc85 [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
59 META/misc_info.txt. (Defaulting to "build/target/product/security"
60 if the value is not present in misc_info.
Doug Zongkereef39442009-04-02 12:14:19 -070061
62 -d and -k options are added to the set of mappings in the order
63 in which they appear on the command line.
Doug Zongker8e931bf2009-04-06 15:21:45 -070064
65 -o (--replace_ota_keys)
Tao Baoa80ed222016-06-16 14:41:24 -070066 Replace the certificate (public key) used by OTA package verification
67 with the ones specified in the input target_files zip (in the
68 META/otakeys.txt file). Key remapping (-k and -d) is performed on the
69 keys. For A/B devices, the payload verification key will be replaced
70 as well. If there're multiple OTA keys, only the first one will be used
71 for payload verification.
Doug Zongker17aa9442009-04-17 10:15:58 -070072
Doug Zongkerae877012009-04-21 10:04:51 -070073 -t (--tag_changes) <+tag>,<-tag>,...
74 Comma-separated list of changes to make to the set of tags (in
75 the last component of the build fingerprint). Prefix each with
76 '+' or '-' to indicate whether that tag should be added or
77 removed. Changes are processed in the order they appear.
Doug Zongker831840e2011-09-22 10:28:04 -070078 Default value is "-test-keys,-dev-keys,+release-keys".
Doug Zongkerae877012009-04-21 10:04:51 -070079
Tao Bao8adcfd12016-06-17 17:01:22 -070080 --replace_verity_private_key <key>
81 Replace the private key used for verity signing. It expects a filename
82 WITHOUT the extension (e.g. verity_key).
83
84 --replace_verity_public_key <key>
85 Replace the certificate (public key) used for verity verification. The
86 key file replaces the one at BOOT/RAMDISK/verity_key (or ROOT/verity_key
87 for devices using system_root_image). It expects the key filename WITH
88 the extension (e.g. verity_key.pub).
89
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -070090 --replace_verity_keyid <path_to_X509_PEM_cert_file>
91 Replace the veritykeyid in BOOT/cmdline of input_target_file_zip
Tao Bao8adcfd12016-06-17 17:01:22 -070092 with keyid of the cert pointed by <path_to_X509_PEM_cert_file>.
Tao Bao639118f2017-06-19 15:48:02 -070093
Bowgo Tsaie4544b12019-02-27 10:15:51 +080094 --avb_{boot,system,system_other,vendor,dtbo,vbmeta}_algorithm <algorithm>
95 --avb_{boot,system,system_other,vendor,dtbo,vbmeta}_key <key>
Tao Bao639118f2017-06-19 15:48:02 -070096 Use the specified algorithm (e.g. SHA256_RSA4096) and the key to AVB-sign
97 the specified image. Otherwise it uses the existing values in info dict.
98
Bowgo Tsaie4544b12019-02-27 10:15:51 +080099 --avb_{apex,boot,system,system_other,vendor,dtbo,vbmeta}_extra_args <args>
Tao Bao639118f2017-06-19 15:48:02 -0700100 Specify any additional args that are needed to AVB-sign the image
101 (e.g. "--signing_helper /path/to/helper"). The args will be appended to
102 the existing ones in info dict.
Doug Zongkereef39442009-04-02 12:14:19 -0700103"""
104
Tao Bao0c28d2d2017-12-24 10:37:38 -0800105from __future__ import print_function
Doug Zongkereef39442009-04-02 12:14:19 -0700106
Robert Craig817c5742013-04-19 10:59:22 -0400107import base64
Doug Zongker8e931bf2009-04-06 15:21:45 -0700108import copy
Robert Craig817c5742013-04-19 10:59:22 -0400109import errno
Narayan Kamatha07bf042017-08-14 14:49:21 +0100110import gzip
Tao Baoaa7e9932019-03-15 09:37:01 -0700111import itertools
Tao Baobadceb22019-03-15 09:33:43 -0700112import logging
Doug Zongkereef39442009-04-02 12:14:19 -0700113import os
114import re
Narayan Kamatha07bf042017-08-14 14:49:21 +0100115import shutil
Tao Bao9fdd00f2017-07-12 11:57:05 -0700116import stat
Doug Zongkereef39442009-04-02 12:14:19 -0700117import subprocess
Tao Bao0c28d2d2017-12-24 10:37:38 -0800118import sys
Doug Zongkereef39442009-04-02 12:14:19 -0700119import tempfile
120import zipfile
Tao Bao66472632017-12-04 17:16:36 -0800121from xml.etree import ElementTree
Doug Zongkereef39442009-04-02 12:14:19 -0700122
Doug Zongker3c84f562014-07-31 11:06:30 -0700123import add_img_to_target_files
Tao Baoaa7e9932019-03-15 09:37:01 -0700124import apex_utils
Doug Zongkereef39442009-04-02 12:14:19 -0700125import common
126
Tao Bao0c28d2d2017-12-24 10:37:38 -0800127
128if sys.hexversion < 0x02070000:
129 print("Python 2.7 or newer is required.", file=sys.stderr)
130 sys.exit(1)
131
132
Tao Baobadceb22019-03-15 09:33:43 -0700133logger = logging.getLogger(__name__)
134
Doug Zongkereef39442009-04-02 12:14:19 -0700135OPTIONS = common.OPTIONS
136
137OPTIONS.extra_apks = {}
Tao Baoaa7e9932019-03-15 09:37:01 -0700138OPTIONS.extra_apex_payload_keys = {}
Tao Bao93c2a012018-06-19 12:19:35 -0700139OPTIONS.skip_apks_with_path_prefix = set()
Doug Zongkereef39442009-04-02 12:14:19 -0700140OPTIONS.key_map = {}
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700141OPTIONS.rebuild_recovery = False
Doug Zongker8e931bf2009-04-06 15:21:45 -0700142OPTIONS.replace_ota_keys = False
Geremy Condraf19b3652014-07-29 17:54:54 -0700143OPTIONS.replace_verity_public_key = False
144OPTIONS.replace_verity_private_key = False
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700145OPTIONS.replace_verity_keyid = False
Doug Zongker831840e2011-09-22 10:28:04 -0700146OPTIONS.tag_changes = ("-test-keys", "-dev-keys", "+release-keys")
Tao Bao639118f2017-06-19 15:48:02 -0700147OPTIONS.avb_keys = {}
148OPTIONS.avb_algorithms = {}
149OPTIONS.avb_extra_args = {}
Doug Zongkereef39442009-04-02 12:14:19 -0700150
Tao Bao0c28d2d2017-12-24 10:37:38 -0800151
Narayan Kamatha07bf042017-08-14 14:49:21 +0100152def GetApkCerts(certmap):
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800153 # apply the key remapping to the contents of the file
154 for apk, cert in certmap.iteritems():
155 certmap[apk] = OPTIONS.key_map.get(cert, cert)
156
157 # apply all the -e options, overriding anything in the file
Doug Zongkerad88c7c2009-04-14 12:34:27 -0700158 for apk, cert in OPTIONS.extra_apks.iteritems():
Doug Zongkerdecf9952009-12-15 17:27:49 -0800159 if not cert:
160 cert = "PRESIGNED"
Doug Zongkerad88c7c2009-04-14 12:34:27 -0700161 certmap[apk] = OPTIONS.key_map.get(cert, cert)
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800162
Doug Zongkereef39442009-04-02 12:14:19 -0700163 return certmap
164
165
Tao Baoaa7e9932019-03-15 09:37:01 -0700166def GetApexKeys(keys_info, key_map):
167 """Gets APEX payload and container signing keys by applying the mapping rules.
168
Tao Baoe1343992019-03-19 12:24:03 -0700169 Presigned payload / container keys will be set accordingly.
Tao Baoaa7e9932019-03-15 09:37:01 -0700170
171 Args:
172 keys_info: A dict that maps from APEX filenames to a tuple of (payload_key,
173 container_key).
174 key_map: A dict that overrides the keys, specified via command-line input.
175
176 Returns:
177 A dict that contains the updated APEX key mapping, which should be used for
178 the current signing.
179 """
180 # Apply all the --extra_apex_payload_key options to override the payload
181 # signing keys in the given keys_info.
182 for apex, key in OPTIONS.extra_apex_payload_keys.items():
Tao Baoe1343992019-03-19 12:24:03 -0700183 if not key:
184 key = 'PRESIGNED'
Tao Baoaa7e9932019-03-15 09:37:01 -0700185 keys_info[apex] = (key, keys_info[apex][1])
186
187 # Apply the key remapping to container keys.
188 for apex, (payload_key, container_key) in keys_info.items():
189 keys_info[apex] = (payload_key, key_map.get(container_key, container_key))
190
191 # Apply all the --extra_apks options to override the container keys.
192 for apex, key in OPTIONS.extra_apks.items():
193 # Skip non-APEX containers.
194 if apex not in keys_info:
195 continue
Tao Baoe1343992019-03-19 12:24:03 -0700196 if not key:
197 key = 'PRESIGNED'
Tao Baofa9de0a2019-03-18 10:24:17 -0700198 keys_info[apex] = (keys_info[apex][0], key_map.get(key, key))
Tao Baoaa7e9932019-03-15 09:37:01 -0700199
200 return keys_info
201
202
Tao Bao93c2a012018-06-19 12:19:35 -0700203def GetApkFileInfo(filename, compressed_extension, skipped_prefixes):
Tao Bao11f955c2018-06-19 12:19:35 -0700204 """Returns the APK info based on the given filename.
205
206 Checks if the given filename (with path) looks like an APK file, by taking the
Tao Bao93c2a012018-06-19 12:19:35 -0700207 compressed extension into consideration. If it appears to be an APK file,
208 further checks if the APK file should be skipped when signing, based on the
209 given path prefixes.
Tao Bao11f955c2018-06-19 12:19:35 -0700210
211 Args:
212 filename: Path to the file.
213 compressed_extension: The extension string of compressed APKs (e.g. ".gz"),
214 or None if there's no compressed APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700215 skipped_prefixes: A set/list/tuple of the path prefixes to be skipped.
Tao Bao11f955c2018-06-19 12:19:35 -0700216
217 Returns:
Tao Bao93c2a012018-06-19 12:19:35 -0700218 (is_apk, is_compressed, should_be_skipped): is_apk indicates whether the
219 given filename is an APK file. is_compressed indicates whether the APK file
220 is compressed (only meaningful when is_apk is True). should_be_skipped
221 indicates whether the filename matches any of the given prefixes to be
222 skipped.
Tao Bao11f955c2018-06-19 12:19:35 -0700223
224 Raises:
Tao Bao93c2a012018-06-19 12:19:35 -0700225 AssertionError: On invalid compressed_extension or skipped_prefixes inputs.
Tao Bao11f955c2018-06-19 12:19:35 -0700226 """
227 assert compressed_extension is None or compressed_extension.startswith('.'), \
228 "Invalid compressed_extension arg: '{}'".format(compressed_extension)
229
Tao Bao93c2a012018-06-19 12:19:35 -0700230 # skipped_prefixes should be one of set/list/tuple types. Other types such as
231 # str shouldn't be accepted.
Tao Baobadceb22019-03-15 09:33:43 -0700232 assert isinstance(skipped_prefixes, (set, list, tuple)), \
233 "Invalid skipped_prefixes input type: {}".format(type(skipped_prefixes))
Tao Bao93c2a012018-06-19 12:19:35 -0700234
Tao Bao11f955c2018-06-19 12:19:35 -0700235 compressed_apk_extension = (
236 ".apk" + compressed_extension if compressed_extension else None)
237 is_apk = (filename.endswith(".apk") or
238 (compressed_apk_extension and
239 filename.endswith(compressed_apk_extension)))
240 if not is_apk:
Tao Bao93c2a012018-06-19 12:19:35 -0700241 return (False, False, False)
Tao Bao11f955c2018-06-19 12:19:35 -0700242
243 is_compressed = (compressed_apk_extension and
244 filename.endswith(compressed_apk_extension))
Tao Bao93c2a012018-06-19 12:19:35 -0700245 should_be_skipped = filename.startswith(tuple(skipped_prefixes))
246 return (True, is_compressed, should_be_skipped)
Tao Bao11f955c2018-06-19 12:19:35 -0700247
248
Tao Baoaa7e9932019-03-15 09:37:01 -0700249def CheckApkAndApexKeysAvailable(input_tf_zip, known_keys,
Tao Baoe1343992019-03-19 12:24:03 -0700250 compressed_extension, apex_keys):
Tao Baoaa7e9932019-03-15 09:37:01 -0700251 """Checks that all the APKs and APEXes have keys specified.
Tao Bao11f955c2018-06-19 12:19:35 -0700252
253 Args:
254 input_tf_zip: An open target_files zip file.
Tao Baoaa7e9932019-03-15 09:37:01 -0700255 known_keys: A set of APKs and APEXes that have known signing keys.
Tao Bao11f955c2018-06-19 12:19:35 -0700256 compressed_extension: The extension string of compressed APKs, such as
Tao Baoaa7e9932019-03-15 09:37:01 -0700257 '.gz', or None if there's no compressed APKs.
Tao Baoe1343992019-03-19 12:24:03 -0700258 apex_keys: A dict that contains the key mapping from APEX name to
259 (payload_key, container_key).
Tao Bao11f955c2018-06-19 12:19:35 -0700260
261 Raises:
Tao Baoaa7e9932019-03-15 09:37:01 -0700262 AssertionError: On finding unknown APKs and APEXes.
Tao Bao11f955c2018-06-19 12:19:35 -0700263 """
Tao Baoaa7e9932019-03-15 09:37:01 -0700264 unknown_files = []
Doug Zongkereb338ef2009-05-20 16:50:49 -0700265 for info in input_tf_zip.infolist():
Tao Baoaa7e9932019-03-15 09:37:01 -0700266 # Handle APEXes first, e.g. SYSTEM/apex/com.android.tzdata.apex.
267 if (info.filename.startswith('SYSTEM/apex') and
268 info.filename.endswith('.apex')):
269 name = os.path.basename(info.filename)
270 if name not in known_keys:
271 unknown_files.append(name)
272 continue
273
274 # And APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700275 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
276 info.filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
277 if not is_apk or should_be_skipped:
Tao Bao11f955c2018-06-19 12:19:35 -0700278 continue
Tao Baoaa7e9932019-03-15 09:37:01 -0700279
Tao Bao11f955c2018-06-19 12:19:35 -0700280 name = os.path.basename(info.filename)
281 if is_compressed:
282 name = name[:-len(compressed_extension)]
Tao Baoaa7e9932019-03-15 09:37:01 -0700283 if name not in known_keys:
284 unknown_files.append(name)
Tao Bao11f955c2018-06-19 12:19:35 -0700285
Tao Baoaa7e9932019-03-15 09:37:01 -0700286 assert not unknown_files, \
Tao Bao11f955c2018-06-19 12:19:35 -0700287 ("No key specified for:\n {}\n"
288 "Use '-e <apkname>=' to specify a key (which may be an empty string to "
Tao Baoaa7e9932019-03-15 09:37:01 -0700289 "not sign this apk).".format("\n ".join(unknown_files)))
Doug Zongkereb338ef2009-05-20 16:50:49 -0700290
Tao Baoe1343992019-03-19 12:24:03 -0700291 # For all the APEXes, double check that we won't have an APEX that has only
292 # one of the payload / container keys set.
293 if not apex_keys:
294 return
295
296 invalid_apexes = []
297 for info in input_tf_zip.infolist():
298 if (not info.filename.startswith('SYSTEM/apex') or
299 not info.filename.endswith('.apex')):
300 continue
301
302 name = os.path.basename(info.filename)
303 (payload_key, container_key) = apex_keys[name]
304 if ((payload_key in common.SPECIAL_CERT_STRINGS and
305 container_key not in common.SPECIAL_CERT_STRINGS) or
306 (payload_key not in common.SPECIAL_CERT_STRINGS and
307 container_key in common.SPECIAL_CERT_STRINGS)):
308 invalid_apexes.append(
309 "{}: payload_key {}, container_key {}".format(
310 name, payload_key, container_key))
311
312 assert not invalid_apexes, \
313 "Invalid APEX keys specified:\n {}\n".format(
314 "\n ".join(invalid_apexes))
315
Doug Zongkereb338ef2009-05-20 16:50:49 -0700316
Narayan Kamatha07bf042017-08-14 14:49:21 +0100317def SignApk(data, keyname, pw, platform_api_level, codename_to_api_level_map,
318 is_compressed):
Doug Zongkereef39442009-04-02 12:14:19 -0700319 unsigned = tempfile.NamedTemporaryFile()
320 unsigned.write(data)
321 unsigned.flush()
322
Narayan Kamatha07bf042017-08-14 14:49:21 +0100323 if is_compressed:
324 uncompressed = tempfile.NamedTemporaryFile()
Tao Bao0c28d2d2017-12-24 10:37:38 -0800325 with gzip.open(unsigned.name, "rb") as in_file, \
326 open(uncompressed.name, "wb") as out_file:
Narayan Kamatha07bf042017-08-14 14:49:21 +0100327 shutil.copyfileobj(in_file, out_file)
328
329 # Finally, close the "unsigned" file (which is gzip compressed), and then
330 # replace it with the uncompressed version.
331 #
332 # TODO(narayan): All this nastiness can be avoided if python 3.2 is in use,
333 # we could just gzip / gunzip in-memory buffers instead.
334 unsigned.close()
335 unsigned = uncompressed
336
Doug Zongkereef39442009-04-02 12:14:19 -0700337 signed = tempfile.NamedTemporaryFile()
338
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800339 # For pre-N builds, don't upgrade to SHA-256 JAR signatures based on the APK's
340 # minSdkVersion to avoid increasing incremental OTA update sizes. If an APK
341 # didn't change, we don't want its signature to change due to the switch
342 # from SHA-1 to SHA-256.
343 # By default, APK signer chooses SHA-256 signatures if the APK's minSdkVersion
344 # is 18 or higher. For pre-N builds we disable this mechanism by pretending
345 # that the APK's minSdkVersion is 1.
346 # For N+ builds, we let APK signer rely on the APK's minSdkVersion to
347 # determine whether to use SHA-256.
348 min_api_level = None
349 if platform_api_level > 23:
350 # Let APK signer choose whether to use SHA-1 or SHA-256, based on the APK's
351 # minSdkVersion attribute
352 min_api_level = None
353 else:
354 # Force APK signer to use SHA-1
355 min_api_level = 1
356
357 common.SignFile(unsigned.name, signed.name, keyname, pw,
Tao Bao0c28d2d2017-12-24 10:37:38 -0800358 min_api_level=min_api_level,
359 codename_to_api_level_map=codename_to_api_level_map)
Doug Zongkereef39442009-04-02 12:14:19 -0700360
Tao Bao0c28d2d2017-12-24 10:37:38 -0800361 data = None
Narayan Kamatha07bf042017-08-14 14:49:21 +0100362 if is_compressed:
363 # Recompress the file after it has been signed.
364 compressed = tempfile.NamedTemporaryFile()
Tao Bao0c28d2d2017-12-24 10:37:38 -0800365 with open(signed.name, "rb") as in_file, \
366 gzip.open(compressed.name, "wb") as out_file:
Narayan Kamatha07bf042017-08-14 14:49:21 +0100367 shutil.copyfileobj(in_file, out_file)
368
369 data = compressed.read()
370 compressed.close()
371 else:
372 data = signed.read()
373
Doug Zongkereef39442009-04-02 12:14:19 -0700374 unsigned.close()
375 signed.close()
376
377 return data
378
379
Tao Baoaa7e9932019-03-15 09:37:01 -0700380def SignApex(apex_data, payload_key, container_key, container_pw,
381 codename_to_api_level_map, signing_args=None):
382 """Signs the current APEX with the given payload/container keys.
383
384 Args:
385 apex_data: Raw APEX data.
Tao Bao9c0f4432019-04-01 21:25:05 -0700386 payload_key: The path to payload signing key (w/ extension).
Tao Baoaa7e9932019-03-15 09:37:01 -0700387 container_key: The path to container signing key (w/o extension).
388 container_pw: The matching password of the container_key, or None.
389 codename_to_api_level_map: A dict that maps from codename to API level.
390 signing_args: Additional args to be passed to the payload signer.
391
392 Returns:
Tao Bao9c0f4432019-04-01 21:25:05 -0700393 The path to the signed APEX file.
Tao Baoaa7e9932019-03-15 09:37:01 -0700394 """
395 apex_file = common.MakeTempFile(prefix='apex-', suffix='.apex')
396 with open(apex_file, 'wb') as apex_fp:
397 apex_fp.write(apex_data)
398
399 APEX_PAYLOAD_IMAGE = 'apex_payload.img'
Tao Bao9c0f4432019-04-01 21:25:05 -0700400 APEX_PUBKEY = 'apex_pubkey'
Tao Baoaa7e9932019-03-15 09:37:01 -0700401
Tao Bao9c0f4432019-04-01 21:25:05 -0700402 # 1a. Extract and sign the APEX_PAYLOAD_IMAGE entry with the given
403 # payload_key.
Tao Baoaa7e9932019-03-15 09:37:01 -0700404 payload_dir = common.MakeTempDir(prefix='apex-payload-')
405 with zipfile.ZipFile(apex_file) as apex_fd:
406 payload_file = apex_fd.extract(APEX_PAYLOAD_IMAGE, payload_dir)
407
408 payload_info = apex_utils.ParseApexPayloadInfo(payload_file)
409 apex_utils.SignApexPayload(
410 payload_file,
411 payload_key,
412 payload_info['apex.key'],
413 payload_info['Algorithm'],
414 payload_info['Salt'],
415 signing_args)
416
Tao Bao9c0f4432019-04-01 21:25:05 -0700417 # 1b. Update the embedded payload public key.
418 payload_public_key = common.ExtractAvbPublicKey(payload_key)
419
Tao Baoaa7e9932019-03-15 09:37:01 -0700420 common.ZipDelete(apex_file, APEX_PAYLOAD_IMAGE)
Tao Bao9c0f4432019-04-01 21:25:05 -0700421 common.ZipDelete(apex_file, APEX_PUBKEY)
Tao Baoaa7e9932019-03-15 09:37:01 -0700422 apex_zip = zipfile.ZipFile(apex_file, 'a')
423 common.ZipWrite(apex_zip, payload_file, arcname=APEX_PAYLOAD_IMAGE)
Tao Bao9c0f4432019-04-01 21:25:05 -0700424 common.ZipWrite(apex_zip, payload_public_key, arcname=APEX_PUBKEY)
Tao Baoaa7e9932019-03-15 09:37:01 -0700425 common.ZipClose(apex_zip)
426
Tao Baoffc9a302019-03-22 23:16:58 -0700427 # 2. Align the files at page boundary (same as in apexer).
428 aligned_apex = common.MakeTempFile(
429 prefix='apex-container-', suffix='.apex')
430 common.RunAndCheckOutput(
431 ['zipalign', '-f', '4096', apex_file, aligned_apex])
432
433 # 3. Sign the APEX container with container_key.
Tao Baoaa7e9932019-03-15 09:37:01 -0700434 signed_apex = common.MakeTempFile(prefix='apex-container-', suffix='.apex')
Tao Baoffc9a302019-03-22 23:16:58 -0700435
436 # Specify the 4K alignment when calling SignApk.
437 extra_signapk_args = OPTIONS.extra_signapk_args[:]
438 extra_signapk_args.extend(['-a', '4096'])
439
Tao Baoaa7e9932019-03-15 09:37:01 -0700440 common.SignFile(
Tao Baoffc9a302019-03-22 23:16:58 -0700441 aligned_apex,
Tao Baoaa7e9932019-03-15 09:37:01 -0700442 signed_apex,
443 container_key,
444 container_pw,
Tao Baoffc9a302019-03-22 23:16:58 -0700445 codename_to_api_level_map=codename_to_api_level_map,
446 extra_signapk_args=extra_signapk_args)
Tao Baoaa7e9932019-03-15 09:37:01 -0700447
Tao Bao9c0f4432019-04-01 21:25:05 -0700448 return signed_apex
Tao Baoaa7e9932019-03-15 09:37:01 -0700449
450
Doug Zongker412c02f2014-02-13 10:58:24 -0800451def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -0700452 apk_keys, apex_keys, key_passwords,
453 platform_api_level, codename_to_api_level_map,
Narayan Kamatha07bf042017-08-14 14:49:21 +0100454 compressed_extension):
Tao Bao93c2a012018-06-19 12:19:35 -0700455 # maxsize measures the maximum filename length, including the ones to be
456 # skipped.
Tao Bao0c28d2d2017-12-24 10:37:38 -0800457 maxsize = max(
458 [len(os.path.basename(i.filename)) for i in input_tf_zip.infolist()
Tao Bao93c2a012018-06-19 12:19:35 -0700459 if GetApkFileInfo(i.filename, compressed_extension, [])[0]])
Tao Baoa80ed222016-06-16 14:41:24 -0700460 system_root_image = misc_info.get("system_root_image") == "true"
Doug Zongker412c02f2014-02-13 10:58:24 -0800461
Doug Zongkereef39442009-04-02 12:14:19 -0700462 for info in input_tf_zip.infolist():
Tao Bao11f955c2018-06-19 12:19:35 -0700463 filename = info.filename
464 if filename.startswith("IMAGES/"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700465 continue
Doug Zongker3c84f562014-07-31 11:06:30 -0700466
Tao Bao33bf2682019-01-11 12:37:35 -0800467 # Skip split super images, which will be re-generated during signing.
468 if filename.startswith("OTA/") and filename.endswith(".img"):
469 continue
470
Tao Bao11f955c2018-06-19 12:19:35 -0700471 data = input_tf_zip.read(filename)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700472 out_info = copy.copy(info)
Tao Bao93c2a012018-06-19 12:19:35 -0700473 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
474 filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
475
476 if is_apk and should_be_skipped:
477 # Copy skipped APKs verbatim.
478 print(
479 "NOT signing: %s\n"
480 " (skipped due to matching prefix)" % (filename,))
481 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker412c02f2014-02-13 10:58:24 -0800482
Tao Baof2cffbd2015-07-22 12:33:18 -0700483 # Sign APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700484 elif is_apk:
Tao Bao11f955c2018-06-19 12:19:35 -0700485 name = os.path.basename(filename)
Narayan Kamatha07bf042017-08-14 14:49:21 +0100486 if is_compressed:
487 name = name[:-len(compressed_extension)]
488
Tao Baoaa7e9932019-03-15 09:37:01 -0700489 key = apk_keys[name]
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800490 if key not in common.SPECIAL_CERT_STRINGS:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800491 print(" signing: %-*s (%s)" % (maxsize, name, key))
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800492 signed_data = SignApk(data, key, key_passwords[key], platform_api_level,
Tao Bao0c28d2d2017-12-24 10:37:38 -0800493 codename_to_api_level_map, is_compressed)
Tao Bao2ed665a2015-04-01 11:21:55 -0700494 common.ZipWriteStr(output_tf_zip, out_info, signed_data)
Doug Zongkereef39442009-04-02 12:14:19 -0700495 else:
496 # an APK we're not supposed to sign.
Tao Bao93c2a012018-06-19 12:19:35 -0700497 print(
498 "NOT signing: %s\n"
499 " (skipped due to special cert string)" % (name,))
Tao Bao2ed665a2015-04-01 11:21:55 -0700500 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoa80ed222016-06-16 14:41:24 -0700501
Tao Baoaa7e9932019-03-15 09:37:01 -0700502 # Sign bundled APEX files.
503 elif filename.startswith("SYSTEM/apex") and filename.endswith(".apex"):
504 name = os.path.basename(filename)
505 payload_key, container_key = apex_keys[name]
506
Tao Baoe1343992019-03-19 12:24:03 -0700507 # We've asserted not having a case with only one of them PRESIGNED.
508 if (payload_key not in common.SPECIAL_CERT_STRINGS and
509 container_key not in common.SPECIAL_CERT_STRINGS):
510 print(" signing: %-*s container (%s)" % (
511 maxsize, name, container_key))
512 print(" : %-*s payload (%s)" % (
513 maxsize, name, payload_key))
Tao Baoaa7e9932019-03-15 09:37:01 -0700514
Tao Bao9c0f4432019-04-01 21:25:05 -0700515 signed_apex = SignApex(
Tao Baoe1343992019-03-19 12:24:03 -0700516 data,
517 payload_key,
518 container_key,
519 key_passwords[container_key],
520 codename_to_api_level_map,
521 OPTIONS.avb_extra_args.get('apex'))
522 common.ZipWrite(output_tf_zip, signed_apex, filename)
Tao Baoaa7e9932019-03-15 09:37:01 -0700523
Tao Baoe1343992019-03-19 12:24:03 -0700524 else:
525 print(
526 "NOT signing: %s\n"
527 " (skipped due to special cert string)" % (name,))
528 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoaa7e9932019-03-15 09:37:01 -0700529
530 # AVB public keys for the installed APEXes, which will be updated later.
531 elif (os.path.dirname(filename) == 'SYSTEM/etc/security/apex' and
532 filename != 'SYSTEM/etc/security/apex/'):
533 continue
534
Tao Baoa80ed222016-06-16 14:41:24 -0700535 # System properties.
Tao Bao11f955c2018-06-19 12:19:35 -0700536 elif filename in ("SYSTEM/build.prop",
537 "VENDOR/build.prop",
Magnus Strandh63967972019-05-01 23:09:30 +0200538 "SYSTEM/vendor/build.prop",
539 "ODM/build.prop",
540 "VENDOR/odm/build.prop",
541 "PRODUCT/build.prop",
542 "SYSTEM/product/build.prop",
543 "PRODUCT_SERVICES/build.prop",
544 "SYSTEM/product_services/build.prop",
Tao Bao11f955c2018-06-19 12:19:35 -0700545 "SYSTEM/etc/prop.default",
546 "BOOT/RAMDISK/prop.default",
547 "BOOT/RAMDISK/default.prop", # legacy
548 "ROOT/default.prop", # legacy
549 "RECOVERY/RAMDISK/prop.default",
550 "RECOVERY/RAMDISK/default.prop"): # legacy
551 print("Rewriting %s:" % (filename,))
Hung-ying Tyan7eb6a922017-05-01 21:56:26 +0800552 if stat.S_ISLNK(info.external_attr >> 16):
553 new_data = data
554 else:
Tao Baoa7054ee2017-12-08 14:42:16 -0800555 new_data = RewriteProps(data)
Tao Bao2ed665a2015-04-01 11:21:55 -0700556 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700557
Tao Bao66472632017-12-04 17:16:36 -0800558 # Replace the certs in *mac_permissions.xml (there could be multiple, such
559 # as {system,vendor}/etc/selinux/{plat,nonplat}_mac_permissions.xml).
Tao Bao11f955c2018-06-19 12:19:35 -0700560 elif filename.endswith("mac_permissions.xml"):
561 print("Rewriting %s with new keys." % (filename,))
Robert Craig817c5742013-04-19 10:59:22 -0400562 new_data = ReplaceCerts(data)
Tao Bao2ed665a2015-04-01 11:21:55 -0700563 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700564
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700565 # Ask add_img_to_target_files to rebuild the recovery patch if needed.
Tao Bao11f955c2018-06-19 12:19:35 -0700566 elif filename in ("SYSTEM/recovery-from-boot.p",
567 "SYSTEM/etc/recovery.img",
568 "SYSTEM/bin/install-recovery.sh"):
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700569 OPTIONS.rebuild_recovery = True
Tao Baoa80ed222016-06-16 14:41:24 -0700570
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700571 # Don't copy OTA certs if we're replacing them.
Tao Bao696bb332018-08-17 16:27:01 -0700572 elif (
573 OPTIONS.replace_ota_keys and
574 filename in (
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700575 "BOOT/RAMDISK/system/etc/security/otacerts.zip",
Tao Bao696bb332018-08-17 16:27:01 -0700576 "BOOT/RAMDISK/system/etc/update_engine/update-payload-key.pub.pem",
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700577 "RECOVERY/RAMDISK/system/etc/security/otacerts.zip",
Tao Bao696bb332018-08-17 16:27:01 -0700578 "SYSTEM/etc/security/otacerts.zip",
579 "SYSTEM/etc/update_engine/update-payload-key.pub.pem")):
Doug Zongker412c02f2014-02-13 10:58:24 -0800580 pass
Tao Baoa80ed222016-06-16 14:41:24 -0700581
Tao Bao46a59992017-06-05 11:55:16 -0700582 # Skip META/misc_info.txt since we will write back the new values later.
Tao Bao11f955c2018-06-19 12:19:35 -0700583 elif filename == "META/misc_info.txt":
Geremy Condraf19b3652014-07-29 17:54:54 -0700584 pass
Tao Bao8adcfd12016-06-17 17:01:22 -0700585
586 # Skip verity public key if we will replace it.
Michael Runge947894f2014-10-14 20:58:38 -0700587 elif (OPTIONS.replace_verity_public_key and
Tao Bao11f955c2018-06-19 12:19:35 -0700588 filename in ("BOOT/RAMDISK/verity_key",
589 "ROOT/verity_key")):
Geremy Condraf19b3652014-07-29 17:54:54 -0700590 pass
Tao Baoa80ed222016-06-16 14:41:24 -0700591
Tao Bao8adcfd12016-06-17 17:01:22 -0700592 # Skip verity keyid (for system_root_image use) if we will replace it.
Tao Bao11f955c2018-06-19 12:19:35 -0700593 elif OPTIONS.replace_verity_keyid and filename == "BOOT/cmdline":
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700594 pass
595
Tianjie Xu4f099002016-08-11 18:04:27 -0700596 # Skip the care_map as we will regenerate the system/vendor images.
Tianjie Xu4c05f4a2018-09-14 16:24:41 -0700597 elif filename == "META/care_map.pb" or filename == "META/care_map.txt":
Tianjie Xu4f099002016-08-11 18:04:27 -0700598 pass
599
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800600 # Updates system_other.avbpubkey in /product/etc/.
601 elif filename in (
602 "PRODUCT/etc/security/avb/system_other.avbpubkey",
603 "SYSTEM/product/etc/security/avb/system_other.avbpubkey"):
604 # Only update system_other's public key, if the corresponding signing
605 # key is specified via --avb_system_other_key.
606 signing_key = OPTIONS.avb_keys.get("system_other")
607 if signing_key:
608 public_key = common.ExtractAvbPublicKey(signing_key)
609 print(" Rewriting AVB public key of system_other in /product")
610 common.ZipWrite(output_tf_zip, public_key, filename)
611
Bowgo Tsai08aca592019-04-23 12:28:44 +0800612 # Should NOT sign boot-debug.img.
613 elif filename in (
614 "BOOT/RAMDISK/force_debuggable",
615 "RECOVERY/RAMDISK/force_debuggable"
616 "RECOVERY/RAMDISK/first_stage_ramdisk/force_debuggable"):
617 raise common.ExternalError("debuggable boot.img cannot be signed")
618
Tao Baoa80ed222016-06-16 14:41:24 -0700619 # A non-APK file; copy it verbatim.
Doug Zongkereef39442009-04-02 12:14:19 -0700620 else:
Tao Bao2ed665a2015-04-01 11:21:55 -0700621 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700622
Doug Zongker412c02f2014-02-13 10:58:24 -0800623 if OPTIONS.replace_ota_keys:
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700624 ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info)
Doug Zongker412c02f2014-02-13 10:58:24 -0800625
Tao Bao46a59992017-06-05 11:55:16 -0700626 # Replace the keyid string in misc_info dict.
Tao Bao8adcfd12016-06-17 17:01:22 -0700627 if OPTIONS.replace_verity_private_key:
Tao Bao46a59992017-06-05 11:55:16 -0700628 ReplaceVerityPrivateKey(misc_info, OPTIONS.replace_verity_private_key[1])
Tao Bao8adcfd12016-06-17 17:01:22 -0700629
630 if OPTIONS.replace_verity_public_key:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800631 dest = "ROOT/verity_key" if system_root_image else "BOOT/RAMDISK/verity_key"
Tao Bao8adcfd12016-06-17 17:01:22 -0700632 # We are replacing the one in boot image only, since the one under
633 # recovery won't ever be needed.
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700634 ReplaceVerityPublicKey(
Tao Bao8adcfd12016-06-17 17:01:22 -0700635 output_tf_zip, dest, OPTIONS.replace_verity_public_key[1])
Tao Bao8adcfd12016-06-17 17:01:22 -0700636
637 # Replace the keyid string in BOOT/cmdline.
638 if OPTIONS.replace_verity_keyid:
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700639 ReplaceVerityKeyId(input_tf_zip, output_tf_zip,
640 OPTIONS.replace_verity_keyid[1])
Doug Zongker412c02f2014-02-13 10:58:24 -0800641
Tao Bao639118f2017-06-19 15:48:02 -0700642 # Replace the AVB signing keys, if any.
643 ReplaceAvbSigningKeys(misc_info)
644
Tao Bao46a59992017-06-05 11:55:16 -0700645 # Write back misc_info with the latest values.
646 ReplaceMiscInfoTxt(input_tf_zip, output_tf_zip, misc_info)
647
Doug Zongker8e931bf2009-04-06 15:21:45 -0700648
Robert Craig817c5742013-04-19 10:59:22 -0400649def ReplaceCerts(data):
Tao Bao66472632017-12-04 17:16:36 -0800650 """Replaces all the occurences of X.509 certs with the new ones.
Robert Craig817c5742013-04-19 10:59:22 -0400651
Tao Bao66472632017-12-04 17:16:36 -0800652 The mapping info is read from OPTIONS.key_map. Non-existent certificate will
653 be skipped. After the replacement, it additionally checks for duplicate
654 entries, which would otherwise fail the policy loading code in
655 frameworks/base/services/core/java/com/android/server/pm/SELinuxMMAC.java.
656
657 Args:
658 data: Input string that contains a set of X.509 certs.
659
660 Returns:
661 A string after the replacement.
662
663 Raises:
664 AssertionError: On finding duplicate entries.
665 """
666 for old, new in OPTIONS.key_map.iteritems():
667 if OPTIONS.verbose:
668 print(" Replacing %s.x509.pem with %s.x509.pem" % (old, new))
669
670 try:
671 with open(old + ".x509.pem") as old_fp:
672 old_cert16 = base64.b16encode(
673 common.ParseCertificate(old_fp.read())).lower()
674 with open(new + ".x509.pem") as new_fp:
675 new_cert16 = base64.b16encode(
676 common.ParseCertificate(new_fp.read())).lower()
677 except IOError as e:
678 if OPTIONS.verbose or e.errno != errno.ENOENT:
679 print(" Error accessing %s: %s.\nSkip replacing %s.x509.pem with "
680 "%s.x509.pem." % (e.filename, e.strerror, old, new))
681 continue
682
683 # Only match entire certs.
684 pattern = "\\b" + old_cert16 + "\\b"
685 (data, num) = re.subn(pattern, new_cert16, data, flags=re.IGNORECASE)
686
687 if OPTIONS.verbose:
688 print(" Replaced %d occurence(s) of %s.x509.pem with %s.x509.pem" % (
689 num, old, new))
690
691 # Verify that there're no duplicate entries after the replacement. Note that
692 # it's only checking entries with global seinfo at the moment (i.e. ignoring
693 # the ones with inner packages). (Bug: 69479366)
694 root = ElementTree.fromstring(data)
695 signatures = [signer.attrib['signature'] for signer in root.findall('signer')]
696 assert len(signatures) == len(set(signatures)), \
697 "Found duplicate entries after cert replacement: {}".format(data)
Robert Craig817c5742013-04-19 10:59:22 -0400698
699 return data
700
701
Doug Zongkerc09abc82010-01-11 13:09:15 -0800702def EditTags(tags):
Tao Baoa7054ee2017-12-08 14:42:16 -0800703 """Applies the edits to the tag string as specified in OPTIONS.tag_changes.
704
705 Args:
706 tags: The input string that contains comma-separated tags.
707
708 Returns:
709 The updated tags (comma-separated and sorted).
710 """
Doug Zongkerc09abc82010-01-11 13:09:15 -0800711 tags = set(tags.split(","))
712 for ch in OPTIONS.tag_changes:
713 if ch[0] == "-":
714 tags.discard(ch[1:])
715 elif ch[0] == "+":
716 tags.add(ch[1:])
717 return ",".join(sorted(tags))
718
719
Tao Baoa7054ee2017-12-08 14:42:16 -0800720def RewriteProps(data):
721 """Rewrites the system properties in the given string.
722
723 Each property is expected in 'key=value' format. The properties that contain
724 build tags (i.e. test-keys, dev-keys) will be updated accordingly by calling
725 EditTags().
726
727 Args:
728 data: Input string, separated by newlines.
729
730 Returns:
731 The string with modified properties.
732 """
Doug Zongker17aa9442009-04-17 10:15:58 -0700733 output = []
734 for line in data.split("\n"):
735 line = line.strip()
736 original_line = line
Michael Rungedc2661a2014-06-03 14:43:11 -0700737 if line and line[0] != '#' and "=" in line:
Doug Zongker17aa9442009-04-17 10:15:58 -0700738 key, value = line.split("=", 1)
Magnus Strandh63967972019-05-01 23:09:30 +0200739 if (key.startswith("ro.") and
740 key.endswith((".build.fingerprint", ".build.thumbprint"))):
Doug Zongkerc09abc82010-01-11 13:09:15 -0800741 pieces = value.split("/")
742 pieces[-1] = EditTags(pieces[-1])
743 value = "/".join(pieces)
Tao Baocb7ff772015-09-11 15:27:56 -0700744 elif key == "ro.bootimage.build.fingerprint":
745 pieces = value.split("/")
746 pieces[-1] = EditTags(pieces[-1])
747 value = "/".join(pieces)
Doug Zongker17aa9442009-04-17 10:15:58 -0700748 elif key == "ro.build.description":
Doug Zongkerc09abc82010-01-11 13:09:15 -0800749 pieces = value.split(" ")
Doug Zongker17aa9442009-04-17 10:15:58 -0700750 assert len(pieces) == 5
Doug Zongkerc09abc82010-01-11 13:09:15 -0800751 pieces[-1] = EditTags(pieces[-1])
752 value = " ".join(pieces)
Magnus Strandh63967972019-05-01 23:09:30 +0200753 elif key.startswith("ro.") and key.endswith(".build.tags"):
Doug Zongkerc09abc82010-01-11 13:09:15 -0800754 value = EditTags(value)
Doug Zongkera8608a72013-07-23 11:51:04 -0700755 elif key == "ro.build.display.id":
756 # change, eg, "JWR66N dev-keys" to "JWR66N"
757 value = value.split()
Michael Rungedc2661a2014-06-03 14:43:11 -0700758 if len(value) > 1 and value[-1].endswith("-keys"):
Andrew Boie73d5abb2013-12-11 12:42:03 -0800759 value.pop()
760 value = " ".join(value)
Doug Zongkerc09abc82010-01-11 13:09:15 -0800761 line = key + "=" + value
Doug Zongker17aa9442009-04-17 10:15:58 -0700762 if line != original_line:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800763 print(" replace: ", original_line)
764 print(" with: ", line)
Doug Zongker17aa9442009-04-17 10:15:58 -0700765 output.append(line)
766 return "\n".join(output) + "\n"
767
768
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700769def WriteOtacerts(output_zip, filename, keys):
770 """Constructs a zipfile from given keys; and writes it to output_zip.
771
772 Args:
773 output_zip: The output target_files zip.
774 filename: The archive name in the output zip.
775 keys: A list of public keys to use during OTA package verification.
776 """
777
778 try:
779 from StringIO import StringIO
780 except ImportError:
781 from io import StringIO
782 temp_file = StringIO()
783 certs_zip = zipfile.ZipFile(temp_file, "w")
784 for k in keys:
785 common.ZipWrite(certs_zip, k)
786 common.ZipClose(certs_zip)
787 common.ZipWriteStr(output_zip, filename, temp_file.getvalue())
788
789
Doug Zongker831840e2011-09-22 10:28:04 -0700790def ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info):
Doug Zongker8e931bf2009-04-06 15:21:45 -0700791 try:
792 keylist = input_tf_zip.read("META/otakeys.txt").split()
793 except KeyError:
T.R. Fullharta28acc62013-03-18 10:31:26 -0700794 raise common.ExternalError("can't read META/otakeys.txt from input")
Doug Zongker8e931bf2009-04-06 15:21:45 -0700795
Tao Baof718f902017-11-09 10:10:10 -0800796 extra_recovery_keys = misc_info.get("extra_recovery_keys")
Doug Zongkere121d6a2011-02-01 14:13:52 -0800797 if extra_recovery_keys:
798 extra_recovery_keys = [OPTIONS.key_map.get(k, k) + ".x509.pem"
799 for k in extra_recovery_keys.split()]
800 if extra_recovery_keys:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800801 print("extra recovery-only key(s): " + ", ".join(extra_recovery_keys))
Doug Zongkere121d6a2011-02-01 14:13:52 -0800802 else:
803 extra_recovery_keys = []
804
Doug Zongker8e931bf2009-04-06 15:21:45 -0700805 mapped_keys = []
806 for k in keylist:
807 m = re.match(r"^(.*)\.x509\.pem$", k)
808 if not m:
Doug Zongker412c02f2014-02-13 10:58:24 -0800809 raise common.ExternalError(
810 "can't parse \"%s\" from META/otakeys.txt" % (k,))
Doug Zongker8e931bf2009-04-06 15:21:45 -0700811 k = m.group(1)
812 mapped_keys.append(OPTIONS.key_map.get(k, k) + ".x509.pem")
813
Doug Zongkere05628c2009-08-20 17:38:42 -0700814 if mapped_keys:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800815 print("using:\n ", "\n ".join(mapped_keys))
816 print("for OTA package verification")
Doug Zongkere05628c2009-08-20 17:38:42 -0700817 else:
Doug Zongker831840e2011-09-22 10:28:04 -0700818 devkey = misc_info.get("default_system_dev_certificate",
819 "build/target/product/security/testkey")
Tao Baof718f902017-11-09 10:10:10 -0800820 mapped_devkey = OPTIONS.key_map.get(devkey, devkey)
821 if mapped_devkey != devkey:
822 misc_info["default_system_dev_certificate"] = mapped_devkey
823 mapped_keys.append(mapped_devkey + ".x509.pem")
Tao Baoa80ed222016-06-16 14:41:24 -0700824 print("META/otakeys.txt has no keys; using %s for OTA package"
825 " verification." % (mapped_keys[0],))
Doug Zongker8e931bf2009-04-06 15:21:45 -0700826
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700827 # recovery now uses the same x509.pem version of the keys.
Doug Zongkere121d6a2011-02-01 14:13:52 -0800828 # extra_recovery_keys are used only in recovery.
Tom Cherry2929cad2018-09-20 11:04:37 -0700829 if misc_info.get("recovery_as_boot") == "true":
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700830 recovery_keys_location = "BOOT/RAMDISK/system/etc/security/otacerts.zip"
Tao Baoa80ed222016-06-16 14:41:24 -0700831 else:
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700832 recovery_keys_location = "RECOVERY/RAMDISK/system/etc/security/otacerts.zip"
833
834 WriteOtacerts(output_tf_zip, recovery_keys_location,
835 mapped_keys + extra_recovery_keys)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700836
837 # SystemUpdateActivity uses the x509.pem version of the keys, but
838 # put into a zipfile system/etc/security/otacerts.zip.
Doug Zongkere121d6a2011-02-01 14:13:52 -0800839 # We DO NOT include the extra_recovery_keys (if any) here.
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700840 WriteOtacerts(output_tf_zip, "SYSTEM/etc/security/otacerts.zip", mapped_keys)
Doug Zongkereef39442009-04-02 12:14:19 -0700841
Tao Baoa80ed222016-06-16 14:41:24 -0700842 # For A/B devices, update the payload verification key.
843 if misc_info.get("ab_update") == "true":
844 # Unlike otacerts.zip that may contain multiple keys, we can only specify
845 # ONE payload verification key.
846 if len(mapped_keys) > 1:
847 print("\n WARNING: Found more than one OTA keys; Using the first one"
848 " as payload verification key.\n\n")
849
Tao Bao0c28d2d2017-12-24 10:37:38 -0800850 print("Using %s for payload verification." % (mapped_keys[0],))
Tao Bao04e1f012018-02-04 12:13:35 -0800851 pubkey = common.ExtractPublicKey(mapped_keys[0])
Tao Bao13b69622016-07-06 15:28:59 -0700852 common.ZipWriteStr(
Tao Baoa80ed222016-06-16 14:41:24 -0700853 output_tf_zip,
Tao Bao13b69622016-07-06 15:28:59 -0700854 "SYSTEM/etc/update_engine/update-payload-key.pub.pem",
855 pubkey)
Alex Deymob3e8ce62016-08-04 16:06:12 -0700856 common.ZipWriteStr(
857 output_tf_zip,
Tao Bao696bb332018-08-17 16:27:01 -0700858 "BOOT/RAMDISK/system/etc/update_engine/update-payload-key.pub.pem",
Alex Deymob3e8ce62016-08-04 16:06:12 -0700859 pubkey)
Tao Baoa80ed222016-06-16 14:41:24 -0700860
Tao Bao8adcfd12016-06-17 17:01:22 -0700861
Tao Bao0c28d2d2017-12-24 10:37:38 -0800862def ReplaceVerityPublicKey(output_zip, filename, key_path):
863 """Replaces the verity public key at the given path in the given zip.
864
865 Args:
866 output_zip: The output target_files zip.
867 filename: The archive name in the output zip.
868 key_path: The path to the public key.
869 """
870 print("Replacing verity public key with %s" % (key_path,))
871 common.ZipWrite(output_zip, key_path, arcname=filename)
Geremy Condraf19b3652014-07-29 17:54:54 -0700872
Tao Bao8adcfd12016-06-17 17:01:22 -0700873
Tao Bao46a59992017-06-05 11:55:16 -0700874def ReplaceVerityPrivateKey(misc_info, key_path):
Tao Bao0c28d2d2017-12-24 10:37:38 -0800875 """Replaces the verity private key in misc_info dict.
876
877 Args:
878 misc_info: The info dict.
879 key_path: The path to the private key in PKCS#8 format.
880 """
881 print("Replacing verity private key with %s" % (key_path,))
Andrew Boied083f0b2014-09-15 16:01:07 -0700882 misc_info["verity_key"] = key_path
Doug Zongkereef39442009-04-02 12:14:19 -0700883
Tao Bao8adcfd12016-06-17 17:01:22 -0700884
Tao Baoe838d142017-12-23 23:44:48 -0800885def ReplaceVerityKeyId(input_zip, output_zip, key_path):
886 """Replaces the veritykeyid parameter in BOOT/cmdline.
887
888 Args:
889 input_zip: The input target_files zip, which should be already open.
890 output_zip: The output target_files zip, which should be already open and
891 writable.
892 key_path: The path to the PEM encoded X.509 certificate.
893 """
894 in_cmdline = input_zip.read("BOOT/cmdline")
895 # Copy in_cmdline to output_zip if veritykeyid is not present.
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700896 if "veritykeyid" not in in_cmdline:
Tao Baoe838d142017-12-23 23:44:48 -0800897 common.ZipWriteStr(output_zip, "BOOT/cmdline", in_cmdline)
898 return
899
Tao Bao0c28d2d2017-12-24 10:37:38 -0800900 out_buffer = []
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700901 for param in in_cmdline.split():
Tao Baoe838d142017-12-23 23:44:48 -0800902 if "veritykeyid" not in param:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800903 out_buffer.append(param)
Tao Baoe838d142017-12-23 23:44:48 -0800904 continue
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700905
Tao Baoe838d142017-12-23 23:44:48 -0800906 # Extract keyid using openssl command.
907 p = common.Run(["openssl", "x509", "-in", key_path, "-text"],
Tao Baode1d4792018-02-20 10:05:46 -0800908 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
Tao Baoe838d142017-12-23 23:44:48 -0800909 keyid, stderr = p.communicate()
910 assert p.returncode == 0, "Failed to dump certificate: {}".format(stderr)
911 keyid = re.search(
912 r'keyid:([0-9a-fA-F:]*)', keyid).group(1).replace(':', '').lower()
913 print("Replacing verity keyid with {}".format(keyid))
914 out_buffer.append("veritykeyid=id:%s" % (keyid,))
915
916 out_cmdline = ' '.join(out_buffer).strip() + '\n'
917 common.ZipWriteStr(output_zip, "BOOT/cmdline", out_cmdline)
Tao Bao46a59992017-06-05 11:55:16 -0700918
919
920def ReplaceMiscInfoTxt(input_zip, output_zip, misc_info):
921 """Replaces META/misc_info.txt.
922
923 Only writes back the ones in the original META/misc_info.txt. Because the
924 current in-memory dict contains additional items computed at runtime.
925 """
926 misc_info_old = common.LoadDictionaryFromLines(
927 input_zip.read('META/misc_info.txt').split('\n'))
928 items = []
929 for key in sorted(misc_info):
930 if key in misc_info_old:
931 items.append('%s=%s' % (key, misc_info[key]))
932 common.ZipWriteStr(output_zip, "META/misc_info.txt", '\n'.join(items))
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700933
Tao Bao8adcfd12016-06-17 17:01:22 -0700934
Tao Bao639118f2017-06-19 15:48:02 -0700935def ReplaceAvbSigningKeys(misc_info):
936 """Replaces the AVB signing keys."""
937
938 AVB_FOOTER_ARGS_BY_PARTITION = {
Tao Bao0c28d2d2017-12-24 10:37:38 -0800939 'boot' : 'avb_boot_add_hash_footer_args',
940 'dtbo' : 'avb_dtbo_add_hash_footer_args',
941 'recovery' : 'avb_recovery_add_hash_footer_args',
942 'system' : 'avb_system_add_hashtree_footer_args',
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800943 'system_other' : 'avb_system_other_add_hashtree_footer_args',
Tao Bao0c28d2d2017-12-24 10:37:38 -0800944 'vendor' : 'avb_vendor_add_hashtree_footer_args',
945 'vbmeta' : 'avb_vbmeta_args',
Tao Bao639118f2017-06-19 15:48:02 -0700946 }
947
948 def ReplaceAvbPartitionSigningKey(partition):
949 key = OPTIONS.avb_keys.get(partition)
950 if not key:
951 return
952
953 algorithm = OPTIONS.avb_algorithms.get(partition)
954 assert algorithm, 'Missing AVB signing algorithm for %s' % (partition,)
955
Tao Bao0c28d2d2017-12-24 10:37:38 -0800956 print('Replacing AVB signing key for %s with "%s" (%s)' % (
957 partition, key, algorithm))
Tao Bao639118f2017-06-19 15:48:02 -0700958 misc_info['avb_' + partition + '_algorithm'] = algorithm
959 misc_info['avb_' + partition + '_key_path'] = key
960
961 extra_args = OPTIONS.avb_extra_args.get(partition)
962 if extra_args:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800963 print('Setting extra AVB signing args for %s to "%s"' % (
964 partition, extra_args))
Tao Bao639118f2017-06-19 15:48:02 -0700965 args_key = AVB_FOOTER_ARGS_BY_PARTITION[partition]
966 misc_info[args_key] = (misc_info.get(args_key, '') + ' ' + extra_args)
967
968 for partition in AVB_FOOTER_ARGS_BY_PARTITION:
969 ReplaceAvbPartitionSigningKey(partition)
970
971
Doug Zongker831840e2011-09-22 10:28:04 -0700972def BuildKeyMap(misc_info, key_mapping_options):
973 for s, d in key_mapping_options:
974 if s is None: # -d option
975 devkey = misc_info.get("default_system_dev_certificate",
976 "build/target/product/security/testkey")
977 devkeydir = os.path.dirname(devkey)
978
979 OPTIONS.key_map.update({
980 devkeydir + "/testkey": d + "/releasekey",
981 devkeydir + "/devkey": d + "/releasekey",
982 devkeydir + "/media": d + "/media",
983 devkeydir + "/shared": d + "/shared",
984 devkeydir + "/platform": d + "/platform",
985 })
986 else:
987 OPTIONS.key_map[s] = d
988
989
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800990def GetApiLevelAndCodename(input_tf_zip):
991 data = input_tf_zip.read("SYSTEM/build.prop")
992 api_level = None
993 codename = None
994 for line in data.split("\n"):
995 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800996 if line and line[0] != '#' and "=" in line:
997 key, value = line.split("=", 1)
998 key = key.strip()
999 if key == "ro.build.version.sdk":
1000 api_level = int(value.strip())
1001 elif key == "ro.build.version.codename":
1002 codename = value.strip()
1003
1004 if api_level is None:
1005 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
1006 if codename is None:
1007 raise ValueError("No ro.build.version.codename in SYSTEM/build.prop")
1008
1009 return (api_level, codename)
1010
1011
1012def GetCodenameToApiLevelMap(input_tf_zip):
1013 data = input_tf_zip.read("SYSTEM/build.prop")
1014 api_level = None
1015 codenames = None
1016 for line in data.split("\n"):
1017 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001018 if line and line[0] != '#' and "=" in line:
1019 key, value = line.split("=", 1)
1020 key = key.strip()
1021 if key == "ro.build.version.sdk":
1022 api_level = int(value.strip())
1023 elif key == "ro.build.version.all_codenames":
1024 codenames = value.strip().split(",")
1025
1026 if api_level is None:
1027 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
1028 if codenames is None:
1029 raise ValueError("No ro.build.version.all_codenames in SYSTEM/build.prop")
1030
1031 result = dict()
1032 for codename in codenames:
1033 codename = codename.strip()
Tao Baobadceb22019-03-15 09:33:43 -07001034 if codename:
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001035 result[codename] = api_level
1036 return result
1037
1038
Tao Baoaa7e9932019-03-15 09:37:01 -07001039def ReadApexKeysInfo(tf_zip):
1040 """Parses the APEX keys info from a given target-files zip.
1041
1042 Given a target-files ZipFile, parses the META/apexkeys.txt entry and returns a
1043 dict that contains the mapping from APEX names (e.g. com.android.tzdata) to a
1044 tuple of (payload_key, container_key).
1045
1046 Args:
1047 tf_zip: The input target_files ZipFile (already open).
1048
1049 Returns:
1050 (payload_key, container_key): payload_key contains the path to the payload
1051 signing key; container_key contains the path to the container signing
1052 key.
1053 """
1054 keys = {}
1055 for line in tf_zip.read("META/apexkeys.txt").split("\n"):
1056 line = line.strip()
1057 if not line:
1058 continue
1059 matches = re.match(
1060 r'^name="(?P<NAME>.*)"\s+'
1061 r'public_key="(?P<PAYLOAD_PUBLIC_KEY>.*)"\s+'
1062 r'private_key="(?P<PAYLOAD_PRIVATE_KEY>.*)"\s+'
1063 r'container_certificate="(?P<CONTAINER_CERT>.*)"\s+'
1064 r'container_private_key="(?P<CONTAINER_PRIVATE_KEY>.*)"$',
1065 line)
1066 if not matches:
1067 continue
1068
1069 name = matches.group('NAME')
Tao Baoaa7e9932019-03-15 09:37:01 -07001070 payload_private_key = matches.group("PAYLOAD_PRIVATE_KEY")
1071
1072 def CompareKeys(pubkey, pubkey_suffix, privkey, privkey_suffix):
1073 pubkey_suffix_len = len(pubkey_suffix)
1074 privkey_suffix_len = len(privkey_suffix)
1075 return (pubkey.endswith(pubkey_suffix) and
1076 privkey.endswith(privkey_suffix) and
1077 pubkey[:-pubkey_suffix_len] == privkey[:-privkey_suffix_len])
1078
Tao Bao6d9e3da2019-03-26 12:59:25 -07001079 # Sanity check on the container key names, as we'll carry them without the
1080 # extensions. This doesn't apply to payload keys though, which we will use
1081 # full names only.
Tao Baoaa7e9932019-03-15 09:37:01 -07001082 container_cert = matches.group("CONTAINER_CERT")
1083 container_private_key = matches.group("CONTAINER_PRIVATE_KEY")
Tao Bao548db7d2019-04-24 23:53:42 -07001084 if container_cert == 'PRESIGNED' and container_private_key == 'PRESIGNED':
1085 container_key = 'PRESIGNED'
1086 elif CompareKeys(
Tao Baoaa7e9932019-03-15 09:37:01 -07001087 container_cert, OPTIONS.public_key_suffix,
1088 container_private_key, OPTIONS.private_key_suffix):
Tao Bao548db7d2019-04-24 23:53:42 -07001089 container_key = container_cert[:-len(OPTIONS.public_key_suffix)]
1090 else:
Tao Baoaa7e9932019-03-15 09:37:01 -07001091 raise ValueError("Failed to parse container keys: \n{}".format(line))
1092
Tao Bao548db7d2019-04-24 23:53:42 -07001093 keys[name] = (payload_private_key, container_key)
Tao Baoaa7e9932019-03-15 09:37:01 -07001094
1095 return keys
1096
1097
Doug Zongkereef39442009-04-02 12:14:19 -07001098def main(argv):
1099
Doug Zongker831840e2011-09-22 10:28:04 -07001100 key_mapping_options = []
1101
Doug Zongkereef39442009-04-02 12:14:19 -07001102 def option_handler(o, a):
Doug Zongker05d3dea2009-06-22 11:32:31 -07001103 if o in ("-e", "--extra_apks"):
Doug Zongkereef39442009-04-02 12:14:19 -07001104 names, key = a.split("=")
1105 names = names.split(",")
1106 for n in names:
1107 OPTIONS.extra_apks[n] = key
Tao Baoaa7e9932019-03-15 09:37:01 -07001108 elif o == "--extra_apex_payload_key":
1109 apex_name, key = a.split("=")
1110 OPTIONS.extra_apex_payload_keys[apex_name] = key
Tao Bao93c2a012018-06-19 12:19:35 -07001111 elif o == "--skip_apks_with_path_prefix":
1112 # Sanity check the prefix, which must be in all upper case.
1113 prefix = a.split('/')[0]
1114 if not prefix or prefix != prefix.upper():
1115 raise ValueError("Invalid path prefix '%s'" % (a,))
1116 OPTIONS.skip_apks_with_path_prefix.add(a)
Doug Zongkereef39442009-04-02 12:14:19 -07001117 elif o in ("-d", "--default_key_mappings"):
Doug Zongker831840e2011-09-22 10:28:04 -07001118 key_mapping_options.append((None, a))
Doug Zongkereef39442009-04-02 12:14:19 -07001119 elif o in ("-k", "--key_mapping"):
Doug Zongker831840e2011-09-22 10:28:04 -07001120 key_mapping_options.append(a.split("=", 1))
Doug Zongker8e931bf2009-04-06 15:21:45 -07001121 elif o in ("-o", "--replace_ota_keys"):
1122 OPTIONS.replace_ota_keys = True
Doug Zongkerae877012009-04-21 10:04:51 -07001123 elif o in ("-t", "--tag_changes"):
1124 new = []
1125 for i in a.split(","):
1126 i = i.strip()
1127 if not i or i[0] not in "-+":
1128 raise ValueError("Bad tag change '%s'" % (i,))
1129 new.append(i[0] + i[1:].strip())
1130 OPTIONS.tag_changes = tuple(new)
Geremy Condraf19b3652014-07-29 17:54:54 -07001131 elif o == "--replace_verity_public_key":
1132 OPTIONS.replace_verity_public_key = (True, a)
1133 elif o == "--replace_verity_private_key":
1134 OPTIONS.replace_verity_private_key = (True, a)
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001135 elif o == "--replace_verity_keyid":
1136 OPTIONS.replace_verity_keyid = (True, a)
Tao Bao639118f2017-06-19 15:48:02 -07001137 elif o == "--avb_vbmeta_key":
1138 OPTIONS.avb_keys['vbmeta'] = a
1139 elif o == "--avb_vbmeta_algorithm":
1140 OPTIONS.avb_algorithms['vbmeta'] = a
1141 elif o == "--avb_vbmeta_extra_args":
1142 OPTIONS.avb_extra_args['vbmeta'] = a
1143 elif o == "--avb_boot_key":
1144 OPTIONS.avb_keys['boot'] = a
1145 elif o == "--avb_boot_algorithm":
1146 OPTIONS.avb_algorithms['boot'] = a
1147 elif o == "--avb_boot_extra_args":
1148 OPTIONS.avb_extra_args['boot'] = a
1149 elif o == "--avb_dtbo_key":
1150 OPTIONS.avb_keys['dtbo'] = a
1151 elif o == "--avb_dtbo_algorithm":
1152 OPTIONS.avb_algorithms['dtbo'] = a
1153 elif o == "--avb_dtbo_extra_args":
1154 OPTIONS.avb_extra_args['dtbo'] = a
1155 elif o == "--avb_system_key":
1156 OPTIONS.avb_keys['system'] = a
1157 elif o == "--avb_system_algorithm":
1158 OPTIONS.avb_algorithms['system'] = a
1159 elif o == "--avb_system_extra_args":
1160 OPTIONS.avb_extra_args['system'] = a
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001161 elif o == "--avb_system_other_key":
1162 OPTIONS.avb_keys['system_other'] = a
1163 elif o == "--avb_system_other_algorithm":
1164 OPTIONS.avb_algorithms['system_other'] = a
1165 elif o == "--avb_system_other_extra_args":
1166 OPTIONS.avb_extra_args['system_other'] = a
Tao Bao639118f2017-06-19 15:48:02 -07001167 elif o == "--avb_vendor_key":
1168 OPTIONS.avb_keys['vendor'] = a
1169 elif o == "--avb_vendor_algorithm":
1170 OPTIONS.avb_algorithms['vendor'] = a
1171 elif o == "--avb_vendor_extra_args":
1172 OPTIONS.avb_extra_args['vendor'] = a
Tao Baoaa7e9932019-03-15 09:37:01 -07001173 elif o == "--avb_apex_extra_args":
1174 OPTIONS.avb_extra_args['apex'] = a
Doug Zongkereef39442009-04-02 12:14:19 -07001175 else:
1176 return False
1177 return True
1178
Tao Bao639118f2017-06-19 15:48:02 -07001179 args = common.ParseOptions(
1180 argv, __doc__,
1181 extra_opts="e:d:k:ot:",
1182 extra_long_opts=[
Tao Bao0c28d2d2017-12-24 10:37:38 -08001183 "extra_apks=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001184 "extra_apex_payload_key=",
Tao Bao93c2a012018-06-19 12:19:35 -07001185 "skip_apks_with_path_prefix=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001186 "default_key_mappings=",
1187 "key_mapping=",
1188 "replace_ota_keys",
1189 "tag_changes=",
1190 "replace_verity_public_key=",
1191 "replace_verity_private_key=",
1192 "replace_verity_keyid=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001193 "avb_apex_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001194 "avb_vbmeta_algorithm=",
1195 "avb_vbmeta_key=",
1196 "avb_vbmeta_extra_args=",
1197 "avb_boot_algorithm=",
1198 "avb_boot_key=",
1199 "avb_boot_extra_args=",
1200 "avb_dtbo_algorithm=",
1201 "avb_dtbo_key=",
1202 "avb_dtbo_extra_args=",
1203 "avb_system_algorithm=",
1204 "avb_system_key=",
1205 "avb_system_extra_args=",
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001206 "avb_system_other_algorithm=",
1207 "avb_system_other_key=",
1208 "avb_system_other_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001209 "avb_vendor_algorithm=",
1210 "avb_vendor_key=",
1211 "avb_vendor_extra_args=",
Tao Bao639118f2017-06-19 15:48:02 -07001212 ],
1213 extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001214
1215 if len(args) != 2:
1216 common.Usage(__doc__)
1217 sys.exit(1)
1218
Tao Baobadceb22019-03-15 09:33:43 -07001219 common.InitLogging()
1220
Doug Zongkereef39442009-04-02 12:14:19 -07001221 input_zip = zipfile.ZipFile(args[0], "r")
Tao Bao2b8f4892017-06-13 12:54:58 -07001222 output_zip = zipfile.ZipFile(args[1], "w",
1223 compression=zipfile.ZIP_DEFLATED,
1224 allowZip64=True)
Doug Zongkereef39442009-04-02 12:14:19 -07001225
Doug Zongker831840e2011-09-22 10:28:04 -07001226 misc_info = common.LoadInfoDict(input_zip)
1227
1228 BuildKeyMap(misc_info, key_mapping_options)
1229
Tao Baoaa7e9932019-03-15 09:37:01 -07001230 apk_keys_info, compressed_extension = common.ReadApkCerts(input_zip)
1231 apk_keys = GetApkCerts(apk_keys_info)
Doug Zongkereb338ef2009-05-20 16:50:49 -07001232
Tao Baoaa7e9932019-03-15 09:37:01 -07001233 apex_keys_info = ReadApexKeysInfo(input_zip)
1234 apex_keys = GetApexKeys(apex_keys_info, apk_keys)
1235
1236 CheckApkAndApexKeysAvailable(
1237 input_zip,
1238 set(apk_keys.keys()) | set(apex_keys.keys()),
Tao Baoe1343992019-03-19 12:24:03 -07001239 compressed_extension,
1240 apex_keys)
Tao Baoaa7e9932019-03-15 09:37:01 -07001241
1242 key_passwords = common.GetKeyPasswords(
1243 set(apk_keys.values()) | set(itertools.chain(*apex_keys.values())))
Tao Bao9aa4b9b2016-09-29 17:53:56 -07001244 platform_api_level, _ = GetApiLevelAndCodename(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001245 codename_to_api_level_map = GetCodenameToApiLevelMap(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001246
Doug Zongker412c02f2014-02-13 10:58:24 -08001247 ProcessTargetFiles(input_zip, output_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -07001248 apk_keys, apex_keys, key_passwords,
1249 platform_api_level, codename_to_api_level_map,
Narayan Kamatha07bf042017-08-14 14:49:21 +01001250 compressed_extension)
Doug Zongker8e931bf2009-04-06 15:21:45 -07001251
Tao Bao2ed665a2015-04-01 11:21:55 -07001252 common.ZipClose(input_zip)
1253 common.ZipClose(output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001254
Tianjie Xub48589a2016-08-03 19:21:52 -07001255 # Skip building userdata.img and cache.img when signing the target files.
Tianjie Xu616fbeb2017-05-23 14:51:02 -07001256 new_args = ["--is_signing"]
1257 # add_img_to_target_files builds the system image from scratch, so the
1258 # recovery patch is guaranteed to be regenerated there.
1259 if OPTIONS.rebuild_recovery:
1260 new_args.append("--rebuild_recovery")
1261 new_args.append(args[1])
Tianjie Xub48589a2016-08-03 19:21:52 -07001262 add_img_to_target_files.main(new_args)
Doug Zongker3c84f562014-07-31 11:06:30 -07001263
Tao Bao0c28d2d2017-12-24 10:37:38 -08001264 print("done.")
Doug Zongkereef39442009-04-02 12:14:19 -07001265
1266
1267if __name__ == '__main__':
1268 try:
1269 main(sys.argv[1:])
Tao Bao0c28d2d2017-12-24 10:37:38 -08001270 except common.ExternalError as e:
1271 print("\n ERROR: %s\n" % (e,))
Doug Zongkereef39442009-04-02 12:14:19 -07001272 sys.exit(1)
Tao Bao639118f2017-06-19 15:48:02 -07001273 finally:
1274 common.Cleanup()