blob: b4d0136db282245ebe7c55382eced47f59167980 [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
Tao Baod403e7b2019-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 Baod403e7b2019-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 Baoaa7e9932019-03-15 09:37:01 -0700114import itertools
Tao Baobadceb22019-03-15 09:33:43 -0700115import logging
Doug Zongkereef39442009-04-02 12:14:19 -0700116import os
117import re
Narayan Kamatha07bf042017-08-14 14:49:21 +0100118import shutil
Tao Bao9fdd00f2017-07-12 11:57:05 -0700119import stat
Doug Zongkereef39442009-04-02 12:14:19 -0700120import subprocess
Tao Bao0c28d2d2017-12-24 10:37:38 -0800121import sys
Doug Zongkereef39442009-04-02 12:14:19 -0700122import tempfile
123import zipfile
Tao Bao66472632017-12-04 17:16:36 -0800124from xml.etree import ElementTree
Doug Zongkereef39442009-04-02 12:14:19 -0700125
Doug Zongker3c84f562014-07-31 11:06:30 -0700126import add_img_to_target_files
Tao Baoaa7e9932019-03-15 09:37:01 -0700127import apex_utils
Doug Zongkereef39442009-04-02 12:14:19 -0700128import common
129
Tao Bao0c28d2d2017-12-24 10:37:38 -0800130
131if sys.hexversion < 0x02070000:
132 print("Python 2.7 or newer is required.", file=sys.stderr)
133 sys.exit(1)
134
135
Tao Baobadceb22019-03-15 09:33:43 -0700136logger = logging.getLogger(__name__)
137
Doug Zongkereef39442009-04-02 12:14:19 -0700138OPTIONS = common.OPTIONS
139
140OPTIONS.extra_apks = {}
Tao Baoaa7e9932019-03-15 09:37:01 -0700141OPTIONS.extra_apex_payload_keys = {}
Tao Bao93c2a012018-06-19 12:19:35 -0700142OPTIONS.skip_apks_with_path_prefix = set()
Doug Zongkereef39442009-04-02 12:14:19 -0700143OPTIONS.key_map = {}
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700144OPTIONS.rebuild_recovery = False
Doug Zongker8e931bf2009-04-06 15:21:45 -0700145OPTIONS.replace_ota_keys = False
Geremy Condraf19b3652014-07-29 17:54:54 -0700146OPTIONS.replace_verity_public_key = False
147OPTIONS.replace_verity_private_key = False
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700148OPTIONS.replace_verity_keyid = False
Doug Zongker831840e2011-09-22 10:28:04 -0700149OPTIONS.tag_changes = ("-test-keys", "-dev-keys", "+release-keys")
Tao Bao639118f2017-06-19 15:48:02 -0700150OPTIONS.avb_keys = {}
151OPTIONS.avb_algorithms = {}
152OPTIONS.avb_extra_args = {}
Doug Zongkereef39442009-04-02 12:14:19 -0700153
Tao Bao0c28d2d2017-12-24 10:37:38 -0800154
Narayan Kamatha07bf042017-08-14 14:49:21 +0100155def GetApkCerts(certmap):
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800156 # apply the key remapping to the contents of the file
157 for apk, cert in certmap.iteritems():
158 certmap[apk] = OPTIONS.key_map.get(cert, cert)
159
160 # apply all the -e options, overriding anything in the file
Doug Zongkerad88c7c2009-04-14 12:34:27 -0700161 for apk, cert in OPTIONS.extra_apks.iteritems():
Doug Zongkerdecf9952009-12-15 17:27:49 -0800162 if not cert:
163 cert = "PRESIGNED"
Doug Zongkerad88c7c2009-04-14 12:34:27 -0700164 certmap[apk] = OPTIONS.key_map.get(cert, cert)
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800165
Doug Zongkereef39442009-04-02 12:14:19 -0700166 return certmap
167
168
Tao Baoaa7e9932019-03-15 09:37:01 -0700169def GetApexKeys(keys_info, key_map):
170 """Gets APEX payload and container signing keys by applying the mapping rules.
171
Tao Baoe1343992019-03-19 12:24:03 -0700172 Presigned payload / container keys will be set accordingly.
Tao Baoaa7e9932019-03-15 09:37:01 -0700173
174 Args:
175 keys_info: A dict that maps from APEX filenames to a tuple of (payload_key,
176 container_key).
177 key_map: A dict that overrides the keys, specified via command-line input.
178
179 Returns:
180 A dict that contains the updated APEX key mapping, which should be used for
181 the current signing.
182 """
183 # Apply all the --extra_apex_payload_key options to override the payload
184 # signing keys in the given keys_info.
185 for apex, key in OPTIONS.extra_apex_payload_keys.items():
Tao Baoe1343992019-03-19 12:24:03 -0700186 if not key:
187 key = 'PRESIGNED'
Tao Baoaa7e9932019-03-15 09:37:01 -0700188 keys_info[apex] = (key, keys_info[apex][1])
189
190 # Apply the key remapping to container keys.
191 for apex, (payload_key, container_key) in keys_info.items():
192 keys_info[apex] = (payload_key, key_map.get(container_key, container_key))
193
194 # Apply all the --extra_apks options to override the container keys.
195 for apex, key in OPTIONS.extra_apks.items():
196 # Skip non-APEX containers.
197 if apex not in keys_info:
198 continue
Tao Baoe1343992019-03-19 12:24:03 -0700199 if not key:
200 key = 'PRESIGNED'
Tao Baofa9de0a2019-03-18 10:24:17 -0700201 keys_info[apex] = (keys_info[apex][0], key_map.get(key, key))
Tao Baoaa7e9932019-03-15 09:37:01 -0700202
203 return keys_info
204
205
Tao Bao93c2a012018-06-19 12:19:35 -0700206def GetApkFileInfo(filename, compressed_extension, skipped_prefixes):
Tao Bao11f955c2018-06-19 12:19:35 -0700207 """Returns the APK info based on the given filename.
208
209 Checks if the given filename (with path) looks like an APK file, by taking the
Tao Bao93c2a012018-06-19 12:19:35 -0700210 compressed extension into consideration. If it appears to be an APK file,
211 further checks if the APK file should be skipped when signing, based on the
212 given path prefixes.
Tao Bao11f955c2018-06-19 12:19:35 -0700213
214 Args:
215 filename: Path to the file.
216 compressed_extension: The extension string of compressed APKs (e.g. ".gz"),
217 or None if there's no compressed APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700218 skipped_prefixes: A set/list/tuple of the path prefixes to be skipped.
Tao Bao11f955c2018-06-19 12:19:35 -0700219
220 Returns:
Tao Bao93c2a012018-06-19 12:19:35 -0700221 (is_apk, is_compressed, should_be_skipped): is_apk indicates whether the
222 given filename is an APK file. is_compressed indicates whether the APK file
223 is compressed (only meaningful when is_apk is True). should_be_skipped
224 indicates whether the filename matches any of the given prefixes to be
225 skipped.
Tao Bao11f955c2018-06-19 12:19:35 -0700226
227 Raises:
Tao Bao93c2a012018-06-19 12:19:35 -0700228 AssertionError: On invalid compressed_extension or skipped_prefixes inputs.
Tao Bao11f955c2018-06-19 12:19:35 -0700229 """
230 assert compressed_extension is None or compressed_extension.startswith('.'), \
231 "Invalid compressed_extension arg: '{}'".format(compressed_extension)
232
Tao Bao93c2a012018-06-19 12:19:35 -0700233 # skipped_prefixes should be one of set/list/tuple types. Other types such as
234 # str shouldn't be accepted.
Tao Baobadceb22019-03-15 09:33:43 -0700235 assert isinstance(skipped_prefixes, (set, list, tuple)), \
236 "Invalid skipped_prefixes input type: {}".format(type(skipped_prefixes))
Tao Bao93c2a012018-06-19 12:19:35 -0700237
Tao Bao11f955c2018-06-19 12:19:35 -0700238 compressed_apk_extension = (
239 ".apk" + compressed_extension if compressed_extension else None)
240 is_apk = (filename.endswith(".apk") or
241 (compressed_apk_extension and
242 filename.endswith(compressed_apk_extension)))
243 if not is_apk:
Tao Bao93c2a012018-06-19 12:19:35 -0700244 return (False, False, False)
Tao Bao11f955c2018-06-19 12:19:35 -0700245
246 is_compressed = (compressed_apk_extension and
247 filename.endswith(compressed_apk_extension))
Tao Bao93c2a012018-06-19 12:19:35 -0700248 should_be_skipped = filename.startswith(tuple(skipped_prefixes))
249 return (True, is_compressed, should_be_skipped)
Tao Bao11f955c2018-06-19 12:19:35 -0700250
251
Tao Baoaa7e9932019-03-15 09:37:01 -0700252def CheckApkAndApexKeysAvailable(input_tf_zip, known_keys,
Tao Baoe1343992019-03-19 12:24:03 -0700253 compressed_extension, apex_keys):
Tao Baoaa7e9932019-03-15 09:37:01 -0700254 """Checks that all the APKs and APEXes have keys specified.
Tao Bao11f955c2018-06-19 12:19:35 -0700255
256 Args:
257 input_tf_zip: An open target_files zip file.
Tao Baoaa7e9932019-03-15 09:37:01 -0700258 known_keys: A set of APKs and APEXes that have known signing keys.
Tao Bao11f955c2018-06-19 12:19:35 -0700259 compressed_extension: The extension string of compressed APKs, such as
Tao Baoaa7e9932019-03-15 09:37:01 -0700260 '.gz', or None if there's no compressed APKs.
Tao Baoe1343992019-03-19 12:24:03 -0700261 apex_keys: A dict that contains the key mapping from APEX name to
262 (payload_key, container_key).
Tao Bao11f955c2018-06-19 12:19:35 -0700263
264 Raises:
Tao Baoaa7e9932019-03-15 09:37:01 -0700265 AssertionError: On finding unknown APKs and APEXes.
Tao Bao11f955c2018-06-19 12:19:35 -0700266 """
Tao Baoaa7e9932019-03-15 09:37:01 -0700267 unknown_files = []
Doug Zongkereb338ef2009-05-20 16:50:49 -0700268 for info in input_tf_zip.infolist():
Tao Baoaa7e9932019-03-15 09:37:01 -0700269 # Handle APEXes first, e.g. SYSTEM/apex/com.android.tzdata.apex.
270 if (info.filename.startswith('SYSTEM/apex') and
271 info.filename.endswith('.apex')):
272 name = os.path.basename(info.filename)
273 if name not in known_keys:
274 unknown_files.append(name)
275 continue
276
277 # And APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700278 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
279 info.filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
280 if not is_apk or should_be_skipped:
Tao Bao11f955c2018-06-19 12:19:35 -0700281 continue
Tao Baoaa7e9932019-03-15 09:37:01 -0700282
Tao Bao11f955c2018-06-19 12:19:35 -0700283 name = os.path.basename(info.filename)
284 if is_compressed:
285 name = name[:-len(compressed_extension)]
Tao Baoaa7e9932019-03-15 09:37:01 -0700286 if name not in known_keys:
287 unknown_files.append(name)
Tao Bao11f955c2018-06-19 12:19:35 -0700288
Tao Baoaa7e9932019-03-15 09:37:01 -0700289 assert not unknown_files, \
Tao Bao11f955c2018-06-19 12:19:35 -0700290 ("No key specified for:\n {}\n"
291 "Use '-e <apkname>=' to specify a key (which may be an empty string to "
Tao Baoaa7e9932019-03-15 09:37:01 -0700292 "not sign this apk).".format("\n ".join(unknown_files)))
Doug Zongkereb338ef2009-05-20 16:50:49 -0700293
Tao Baoe1343992019-03-19 12:24:03 -0700294 # For all the APEXes, double check that we won't have an APEX that has only
295 # one of the payload / container keys set.
296 if not apex_keys:
297 return
298
299 invalid_apexes = []
300 for info in input_tf_zip.infolist():
301 if (not info.filename.startswith('SYSTEM/apex') or
302 not info.filename.endswith('.apex')):
303 continue
304
305 name = os.path.basename(info.filename)
306 (payload_key, container_key) = apex_keys[name]
307 if ((payload_key in common.SPECIAL_CERT_STRINGS and
308 container_key not in common.SPECIAL_CERT_STRINGS) or
309 (payload_key not in common.SPECIAL_CERT_STRINGS and
310 container_key in common.SPECIAL_CERT_STRINGS)):
311 invalid_apexes.append(
312 "{}: payload_key {}, container_key {}".format(
313 name, payload_key, container_key))
314
315 assert not invalid_apexes, \
316 "Invalid APEX keys specified:\n {}\n".format(
317 "\n ".join(invalid_apexes))
318
Doug Zongkereb338ef2009-05-20 16:50:49 -0700319
Narayan Kamatha07bf042017-08-14 14:49:21 +0100320def SignApk(data, keyname, pw, platform_api_level, codename_to_api_level_map,
321 is_compressed):
Doug Zongkereef39442009-04-02 12:14:19 -0700322 unsigned = tempfile.NamedTemporaryFile()
323 unsigned.write(data)
324 unsigned.flush()
325
Narayan Kamatha07bf042017-08-14 14:49:21 +0100326 if is_compressed:
327 uncompressed = tempfile.NamedTemporaryFile()
Tao Bao0c28d2d2017-12-24 10:37:38 -0800328 with gzip.open(unsigned.name, "rb") as in_file, \
329 open(uncompressed.name, "wb") as out_file:
Narayan Kamatha07bf042017-08-14 14:49:21 +0100330 shutil.copyfileobj(in_file, out_file)
331
332 # Finally, close the "unsigned" file (which is gzip compressed), and then
333 # replace it with the uncompressed version.
334 #
335 # TODO(narayan): All this nastiness can be avoided if python 3.2 is in use,
336 # we could just gzip / gunzip in-memory buffers instead.
337 unsigned.close()
338 unsigned = uncompressed
339
Doug Zongkereef39442009-04-02 12:14:19 -0700340 signed = tempfile.NamedTemporaryFile()
341
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800342 # For pre-N builds, don't upgrade to SHA-256 JAR signatures based on the APK's
343 # minSdkVersion to avoid increasing incremental OTA update sizes. If an APK
344 # didn't change, we don't want its signature to change due to the switch
345 # from SHA-1 to SHA-256.
346 # By default, APK signer chooses SHA-256 signatures if the APK's minSdkVersion
347 # is 18 or higher. For pre-N builds we disable this mechanism by pretending
348 # that the APK's minSdkVersion is 1.
349 # For N+ builds, we let APK signer rely on the APK's minSdkVersion to
350 # determine whether to use SHA-256.
351 min_api_level = None
352 if platform_api_level > 23:
353 # Let APK signer choose whether to use SHA-1 or SHA-256, based on the APK's
354 # minSdkVersion attribute
355 min_api_level = None
356 else:
357 # Force APK signer to use SHA-1
358 min_api_level = 1
359
360 common.SignFile(unsigned.name, signed.name, keyname, pw,
Tao Bao0c28d2d2017-12-24 10:37:38 -0800361 min_api_level=min_api_level,
362 codename_to_api_level_map=codename_to_api_level_map)
Doug Zongkereef39442009-04-02 12:14:19 -0700363
Tao Bao0c28d2d2017-12-24 10:37:38 -0800364 data = None
Narayan Kamatha07bf042017-08-14 14:49:21 +0100365 if is_compressed:
366 # Recompress the file after it has been signed.
367 compressed = tempfile.NamedTemporaryFile()
Tao Bao0c28d2d2017-12-24 10:37:38 -0800368 with open(signed.name, "rb") as in_file, \
369 gzip.open(compressed.name, "wb") as out_file:
Narayan Kamatha07bf042017-08-14 14:49:21 +0100370 shutil.copyfileobj(in_file, out_file)
371
372 data = compressed.read()
373 compressed.close()
374 else:
375 data = signed.read()
376
Doug Zongkereef39442009-04-02 12:14:19 -0700377 unsigned.close()
378 signed.close()
379
380 return data
381
382
Tao Baoaa7e9932019-03-15 09:37:01 -0700383def SignApex(apex_data, payload_key, container_key, container_pw,
384 codename_to_api_level_map, signing_args=None):
385 """Signs the current APEX with the given payload/container keys.
386
387 Args:
388 apex_data: Raw APEX data.
Tao Bao9c0f4432019-04-01 21:25:05 -0700389 payload_key: The path to payload signing key (w/ extension).
Tao Baoaa7e9932019-03-15 09:37:01 -0700390 container_key: The path to container signing key (w/o extension).
391 container_pw: The matching password of the container_key, or None.
392 codename_to_api_level_map: A dict that maps from codename to API level.
393 signing_args: Additional args to be passed to the payload signer.
394
395 Returns:
Tao Bao9c0f4432019-04-01 21:25:05 -0700396 The path to the signed APEX file.
Tao Baoaa7e9932019-03-15 09:37:01 -0700397 """
398 apex_file = common.MakeTempFile(prefix='apex-', suffix='.apex')
399 with open(apex_file, 'wb') as apex_fp:
400 apex_fp.write(apex_data)
401
402 APEX_PAYLOAD_IMAGE = 'apex_payload.img'
Tao Bao9c0f4432019-04-01 21:25:05 -0700403 APEX_PUBKEY = 'apex_pubkey'
Tao Baoaa7e9932019-03-15 09:37:01 -0700404
Tao Bao9c0f4432019-04-01 21:25:05 -0700405 # 1a. Extract and sign the APEX_PAYLOAD_IMAGE entry with the given
406 # payload_key.
Tao Baoaa7e9932019-03-15 09:37:01 -0700407 payload_dir = common.MakeTempDir(prefix='apex-payload-')
408 with zipfile.ZipFile(apex_file) as apex_fd:
409 payload_file = apex_fd.extract(APEX_PAYLOAD_IMAGE, payload_dir)
410
411 payload_info = apex_utils.ParseApexPayloadInfo(payload_file)
412 apex_utils.SignApexPayload(
413 payload_file,
414 payload_key,
415 payload_info['apex.key'],
416 payload_info['Algorithm'],
417 payload_info['Salt'],
418 signing_args)
419
Tao Bao9c0f4432019-04-01 21:25:05 -0700420 # 1b. Update the embedded payload public key.
421 payload_public_key = common.ExtractAvbPublicKey(payload_key)
422
Tao Baoaa7e9932019-03-15 09:37:01 -0700423 common.ZipDelete(apex_file, APEX_PAYLOAD_IMAGE)
Tao Bao9c0f4432019-04-01 21:25:05 -0700424 common.ZipDelete(apex_file, APEX_PUBKEY)
Tao Baoaa7e9932019-03-15 09:37:01 -0700425 apex_zip = zipfile.ZipFile(apex_file, 'a')
426 common.ZipWrite(apex_zip, payload_file, arcname=APEX_PAYLOAD_IMAGE)
Tao Bao9c0f4432019-04-01 21:25:05 -0700427 common.ZipWrite(apex_zip, payload_public_key, arcname=APEX_PUBKEY)
Tao Baoaa7e9932019-03-15 09:37:01 -0700428 common.ZipClose(apex_zip)
429
Tao Baoffc9a302019-03-22 23:16:58 -0700430 # 2. Align the files at page boundary (same as in apexer).
431 aligned_apex = common.MakeTempFile(
432 prefix='apex-container-', suffix='.apex')
433 common.RunAndCheckOutput(
434 ['zipalign', '-f', '4096', apex_file, aligned_apex])
435
436 # 3. Sign the APEX container with container_key.
Tao Baoaa7e9932019-03-15 09:37:01 -0700437 signed_apex = common.MakeTempFile(prefix='apex-container-', suffix='.apex')
Tao Baoffc9a302019-03-22 23:16:58 -0700438
439 # Specify the 4K alignment when calling SignApk.
440 extra_signapk_args = OPTIONS.extra_signapk_args[:]
441 extra_signapk_args.extend(['-a', '4096'])
442
Tao Baoaa7e9932019-03-15 09:37:01 -0700443 common.SignFile(
Tao Baoffc9a302019-03-22 23:16:58 -0700444 aligned_apex,
Tao Baoaa7e9932019-03-15 09:37:01 -0700445 signed_apex,
446 container_key,
447 container_pw,
Tao Baoffc9a302019-03-22 23:16:58 -0700448 codename_to_api_level_map=codename_to_api_level_map,
449 extra_signapk_args=extra_signapk_args)
Tao Baoaa7e9932019-03-15 09:37:01 -0700450
Tao Bao9c0f4432019-04-01 21:25:05 -0700451 return signed_apex
Tao Baoaa7e9932019-03-15 09:37:01 -0700452
453
Doug Zongker412c02f2014-02-13 10:58:24 -0800454def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -0700455 apk_keys, apex_keys, key_passwords,
456 platform_api_level, codename_to_api_level_map,
Narayan Kamatha07bf042017-08-14 14:49:21 +0100457 compressed_extension):
Tao Bao93c2a012018-06-19 12:19:35 -0700458 # maxsize measures the maximum filename length, including the ones to be
459 # skipped.
Tao Bao0c28d2d2017-12-24 10:37:38 -0800460 maxsize = max(
461 [len(os.path.basename(i.filename)) for i in input_tf_zip.infolist()
Tao Bao93c2a012018-06-19 12:19:35 -0700462 if GetApkFileInfo(i.filename, compressed_extension, [])[0]])
Tao Baoa80ed222016-06-16 14:41:24 -0700463 system_root_image = misc_info.get("system_root_image") == "true"
Doug Zongker412c02f2014-02-13 10:58:24 -0800464
Doug Zongkereef39442009-04-02 12:14:19 -0700465 for info in input_tf_zip.infolist():
Tao Bao11f955c2018-06-19 12:19:35 -0700466 filename = info.filename
467 if filename.startswith("IMAGES/"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700468 continue
Doug Zongker3c84f562014-07-31 11:06:30 -0700469
Tao Bao33bf2682019-01-11 12:37:35 -0800470 # Skip split super images, which will be re-generated during signing.
471 if filename.startswith("OTA/") and filename.endswith(".img"):
472 continue
473
Tao Bao11f955c2018-06-19 12:19:35 -0700474 data = input_tf_zip.read(filename)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700475 out_info = copy.copy(info)
Tao Bao93c2a012018-06-19 12:19:35 -0700476 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
477 filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
478
479 if is_apk and should_be_skipped:
480 # Copy skipped APKs verbatim.
481 print(
482 "NOT signing: %s\n"
483 " (skipped due to matching prefix)" % (filename,))
484 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker412c02f2014-02-13 10:58:24 -0800485
Tao Baof2cffbd2015-07-22 12:33:18 -0700486 # Sign APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700487 elif is_apk:
Tao Bao11f955c2018-06-19 12:19:35 -0700488 name = os.path.basename(filename)
Narayan Kamatha07bf042017-08-14 14:49:21 +0100489 if is_compressed:
490 name = name[:-len(compressed_extension)]
491
Tao Baoaa7e9932019-03-15 09:37:01 -0700492 key = apk_keys[name]
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800493 if key not in common.SPECIAL_CERT_STRINGS:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800494 print(" signing: %-*s (%s)" % (maxsize, name, key))
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800495 signed_data = SignApk(data, key, key_passwords[key], platform_api_level,
Tao Bao0c28d2d2017-12-24 10:37:38 -0800496 codename_to_api_level_map, is_compressed)
Tao Bao2ed665a2015-04-01 11:21:55 -0700497 common.ZipWriteStr(output_tf_zip, out_info, signed_data)
Doug Zongkereef39442009-04-02 12:14:19 -0700498 else:
499 # an APK we're not supposed to sign.
Tao Bao93c2a012018-06-19 12:19:35 -0700500 print(
501 "NOT signing: %s\n"
502 " (skipped due to special cert string)" % (name,))
Tao Bao2ed665a2015-04-01 11:21:55 -0700503 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoa80ed222016-06-16 14:41:24 -0700504
Tao Baoaa7e9932019-03-15 09:37:01 -0700505 # Sign bundled APEX files.
506 elif filename.startswith("SYSTEM/apex") and filename.endswith(".apex"):
507 name = os.path.basename(filename)
508 payload_key, container_key = apex_keys[name]
509
Tao Baoe1343992019-03-19 12:24:03 -0700510 # We've asserted not having a case with only one of them PRESIGNED.
511 if (payload_key not in common.SPECIAL_CERT_STRINGS and
512 container_key not in common.SPECIAL_CERT_STRINGS):
513 print(" signing: %-*s container (%s)" % (
514 maxsize, name, container_key))
515 print(" : %-*s payload (%s)" % (
516 maxsize, name, payload_key))
Tao Baoaa7e9932019-03-15 09:37:01 -0700517
Tao Bao9c0f4432019-04-01 21:25:05 -0700518 signed_apex = SignApex(
Tao Baoe1343992019-03-19 12:24:03 -0700519 data,
520 payload_key,
521 container_key,
522 key_passwords[container_key],
523 codename_to_api_level_map,
524 OPTIONS.avb_extra_args.get('apex'))
525 common.ZipWrite(output_tf_zip, signed_apex, filename)
Tao Baoaa7e9932019-03-15 09:37:01 -0700526
Tao Baoe1343992019-03-19 12:24:03 -0700527 else:
528 print(
529 "NOT signing: %s\n"
530 " (skipped due to special cert string)" % (name,))
531 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoaa7e9932019-03-15 09:37:01 -0700532
533 # AVB public keys for the installed APEXes, which will be updated later.
534 elif (os.path.dirname(filename) == 'SYSTEM/etc/security/apex' and
535 filename != 'SYSTEM/etc/security/apex/'):
536 continue
537
Tao Baoa80ed222016-06-16 14:41:24 -0700538 # System properties.
Tao Bao11f955c2018-06-19 12:19:35 -0700539 elif filename in ("SYSTEM/build.prop",
540 "VENDOR/build.prop",
Magnus Strandh63967972019-05-01 23:09:30 +0200541 "SYSTEM/vendor/build.prop",
542 "ODM/build.prop",
543 "VENDOR/odm/build.prop",
544 "PRODUCT/build.prop",
545 "SYSTEM/product/build.prop",
546 "PRODUCT_SERVICES/build.prop",
547 "SYSTEM/product_services/build.prop",
Tao Bao11f955c2018-06-19 12:19:35 -0700548 "SYSTEM/etc/prop.default",
549 "BOOT/RAMDISK/prop.default",
550 "BOOT/RAMDISK/default.prop", # legacy
551 "ROOT/default.prop", # legacy
552 "RECOVERY/RAMDISK/prop.default",
553 "RECOVERY/RAMDISK/default.prop"): # legacy
554 print("Rewriting %s:" % (filename,))
Hung-ying Tyan7eb6a922017-05-01 21:56:26 +0800555 if stat.S_ISLNK(info.external_attr >> 16):
556 new_data = data
557 else:
Tao Baoa7054ee2017-12-08 14:42:16 -0800558 new_data = RewriteProps(data)
Tao Bao2ed665a2015-04-01 11:21:55 -0700559 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700560
Tao Bao66472632017-12-04 17:16:36 -0800561 # Replace the certs in *mac_permissions.xml (there could be multiple, such
562 # as {system,vendor}/etc/selinux/{plat,nonplat}_mac_permissions.xml).
Tao Bao11f955c2018-06-19 12:19:35 -0700563 elif filename.endswith("mac_permissions.xml"):
564 print("Rewriting %s with new keys." % (filename,))
Robert Craig817c5742013-04-19 10:59:22 -0400565 new_data = ReplaceCerts(data)
Tao Bao2ed665a2015-04-01 11:21:55 -0700566 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700567
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700568 # Ask add_img_to_target_files to rebuild the recovery patch if needed.
Tao Bao11f955c2018-06-19 12:19:35 -0700569 elif filename in ("SYSTEM/recovery-from-boot.p",
570 "SYSTEM/etc/recovery.img",
571 "SYSTEM/bin/install-recovery.sh"):
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700572 OPTIONS.rebuild_recovery = True
Tao Baoa80ed222016-06-16 14:41:24 -0700573
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700574 # Don't copy OTA certs if we're replacing them.
Tao Bao696bb332018-08-17 16:27:01 -0700575 elif (
576 OPTIONS.replace_ota_keys and
577 filename in (
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700578 "BOOT/RAMDISK/system/etc/security/otacerts.zip",
Tao Bao696bb332018-08-17 16:27:01 -0700579 "BOOT/RAMDISK/system/etc/update_engine/update-payload-key.pub.pem",
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700580 "RECOVERY/RAMDISK/system/etc/security/otacerts.zip",
Tao Bao696bb332018-08-17 16:27:01 -0700581 "SYSTEM/etc/security/otacerts.zip",
582 "SYSTEM/etc/update_engine/update-payload-key.pub.pem")):
Doug Zongker412c02f2014-02-13 10:58:24 -0800583 pass
Tao Baoa80ed222016-06-16 14:41:24 -0700584
Tao Bao46a59992017-06-05 11:55:16 -0700585 # Skip META/misc_info.txt since we will write back the new values later.
Tao Bao11f955c2018-06-19 12:19:35 -0700586 elif filename == "META/misc_info.txt":
Geremy Condraf19b3652014-07-29 17:54:54 -0700587 pass
Tao Bao8adcfd12016-06-17 17:01:22 -0700588
589 # Skip verity public key if we will replace it.
Michael Runge947894f2014-10-14 20:58:38 -0700590 elif (OPTIONS.replace_verity_public_key and
Tao Bao11f955c2018-06-19 12:19:35 -0700591 filename in ("BOOT/RAMDISK/verity_key",
592 "ROOT/verity_key")):
Geremy Condraf19b3652014-07-29 17:54:54 -0700593 pass
Tao Baoa80ed222016-06-16 14:41:24 -0700594
Tao Bao8adcfd12016-06-17 17:01:22 -0700595 # Skip verity keyid (for system_root_image use) if we will replace it.
Tao Bao11f955c2018-06-19 12:19:35 -0700596 elif OPTIONS.replace_verity_keyid and filename == "BOOT/cmdline":
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700597 pass
598
Tianjie Xu4f099002016-08-11 18:04:27 -0700599 # Skip the care_map as we will regenerate the system/vendor images.
Tianjie Xu4c05f4a2018-09-14 16:24:41 -0700600 elif filename == "META/care_map.pb" or filename == "META/care_map.txt":
Tianjie Xu4f099002016-08-11 18:04:27 -0700601 pass
602
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800603 # Updates system_other.avbpubkey in /product/etc/.
604 elif filename in (
605 "PRODUCT/etc/security/avb/system_other.avbpubkey",
606 "SYSTEM/product/etc/security/avb/system_other.avbpubkey"):
607 # Only update system_other's public key, if the corresponding signing
608 # key is specified via --avb_system_other_key.
609 signing_key = OPTIONS.avb_keys.get("system_other")
610 if signing_key:
611 public_key = common.ExtractAvbPublicKey(signing_key)
612 print(" Rewriting AVB public key of system_other in /product")
613 common.ZipWrite(output_tf_zip, public_key, filename)
614
Bowgo Tsai08aca592019-04-23 12:28:44 +0800615 # Should NOT sign boot-debug.img.
616 elif filename in (
617 "BOOT/RAMDISK/force_debuggable",
618 "RECOVERY/RAMDISK/force_debuggable"
619 "RECOVERY/RAMDISK/first_stage_ramdisk/force_debuggable"):
620 raise common.ExternalError("debuggable boot.img cannot be signed")
621
Tao Baoa80ed222016-06-16 14:41:24 -0700622 # A non-APK file; copy it verbatim.
Doug Zongkereef39442009-04-02 12:14:19 -0700623 else:
Tao Bao2ed665a2015-04-01 11:21:55 -0700624 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700625
Doug Zongker412c02f2014-02-13 10:58:24 -0800626 if OPTIONS.replace_ota_keys:
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700627 ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info)
Doug Zongker412c02f2014-02-13 10:58:24 -0800628
Tao Bao46a59992017-06-05 11:55:16 -0700629 # Replace the keyid string in misc_info dict.
Tao Bao8adcfd12016-06-17 17:01:22 -0700630 if OPTIONS.replace_verity_private_key:
Tao Bao46a59992017-06-05 11:55:16 -0700631 ReplaceVerityPrivateKey(misc_info, OPTIONS.replace_verity_private_key[1])
Tao Bao8adcfd12016-06-17 17:01:22 -0700632
633 if OPTIONS.replace_verity_public_key:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800634 dest = "ROOT/verity_key" if system_root_image else "BOOT/RAMDISK/verity_key"
Tao Bao8adcfd12016-06-17 17:01:22 -0700635 # We are replacing the one in boot image only, since the one under
636 # recovery won't ever be needed.
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700637 ReplaceVerityPublicKey(
Tao Bao8adcfd12016-06-17 17:01:22 -0700638 output_tf_zip, dest, OPTIONS.replace_verity_public_key[1])
Tao Bao8adcfd12016-06-17 17:01:22 -0700639
640 # Replace the keyid string in BOOT/cmdline.
641 if OPTIONS.replace_verity_keyid:
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700642 ReplaceVerityKeyId(input_tf_zip, output_tf_zip,
643 OPTIONS.replace_verity_keyid[1])
Doug Zongker412c02f2014-02-13 10:58:24 -0800644
Tao Bao639118f2017-06-19 15:48:02 -0700645 # Replace the AVB signing keys, if any.
646 ReplaceAvbSigningKeys(misc_info)
647
Tao Bao46a59992017-06-05 11:55:16 -0700648 # Write back misc_info with the latest values.
649 ReplaceMiscInfoTxt(input_tf_zip, output_tf_zip, misc_info)
650
Doug Zongker8e931bf2009-04-06 15:21:45 -0700651
Robert Craig817c5742013-04-19 10:59:22 -0400652def ReplaceCerts(data):
Tao Bao66472632017-12-04 17:16:36 -0800653 """Replaces all the occurences of X.509 certs with the new ones.
Robert Craig817c5742013-04-19 10:59:22 -0400654
Tao Bao66472632017-12-04 17:16:36 -0800655 The mapping info is read from OPTIONS.key_map. Non-existent certificate will
656 be skipped. After the replacement, it additionally checks for duplicate
657 entries, which would otherwise fail the policy loading code in
658 frameworks/base/services/core/java/com/android/server/pm/SELinuxMMAC.java.
659
660 Args:
661 data: Input string that contains a set of X.509 certs.
662
663 Returns:
664 A string after the replacement.
665
666 Raises:
667 AssertionError: On finding duplicate entries.
668 """
669 for old, new in OPTIONS.key_map.iteritems():
670 if OPTIONS.verbose:
671 print(" Replacing %s.x509.pem with %s.x509.pem" % (old, new))
672
673 try:
674 with open(old + ".x509.pem") as old_fp:
675 old_cert16 = base64.b16encode(
676 common.ParseCertificate(old_fp.read())).lower()
677 with open(new + ".x509.pem") as new_fp:
678 new_cert16 = base64.b16encode(
679 common.ParseCertificate(new_fp.read())).lower()
680 except IOError as e:
681 if OPTIONS.verbose or e.errno != errno.ENOENT:
682 print(" Error accessing %s: %s.\nSkip replacing %s.x509.pem with "
683 "%s.x509.pem." % (e.filename, e.strerror, old, new))
684 continue
685
686 # Only match entire certs.
687 pattern = "\\b" + old_cert16 + "\\b"
688 (data, num) = re.subn(pattern, new_cert16, data, flags=re.IGNORECASE)
689
690 if OPTIONS.verbose:
691 print(" Replaced %d occurence(s) of %s.x509.pem with %s.x509.pem" % (
692 num, old, new))
693
694 # Verify that there're no duplicate entries after the replacement. Note that
695 # it's only checking entries with global seinfo at the moment (i.e. ignoring
696 # the ones with inner packages). (Bug: 69479366)
697 root = ElementTree.fromstring(data)
698 signatures = [signer.attrib['signature'] for signer in root.findall('signer')]
699 assert len(signatures) == len(set(signatures)), \
700 "Found duplicate entries after cert replacement: {}".format(data)
Robert Craig817c5742013-04-19 10:59:22 -0400701
702 return data
703
704
Doug Zongkerc09abc82010-01-11 13:09:15 -0800705def EditTags(tags):
Tao Baoa7054ee2017-12-08 14:42:16 -0800706 """Applies the edits to the tag string as specified in OPTIONS.tag_changes.
707
708 Args:
709 tags: The input string that contains comma-separated tags.
710
711 Returns:
712 The updated tags (comma-separated and sorted).
713 """
Doug Zongkerc09abc82010-01-11 13:09:15 -0800714 tags = set(tags.split(","))
715 for ch in OPTIONS.tag_changes:
716 if ch[0] == "-":
717 tags.discard(ch[1:])
718 elif ch[0] == "+":
719 tags.add(ch[1:])
720 return ",".join(sorted(tags))
721
722
Tao Baoa7054ee2017-12-08 14:42:16 -0800723def RewriteProps(data):
724 """Rewrites the system properties in the given string.
725
726 Each property is expected in 'key=value' format. The properties that contain
727 build tags (i.e. test-keys, dev-keys) will be updated accordingly by calling
728 EditTags().
729
730 Args:
731 data: Input string, separated by newlines.
732
733 Returns:
734 The string with modified properties.
735 """
Doug Zongker17aa9442009-04-17 10:15:58 -0700736 output = []
737 for line in data.split("\n"):
738 line = line.strip()
739 original_line = line
Michael Rungedc2661a2014-06-03 14:43:11 -0700740 if line and line[0] != '#' and "=" in line:
Doug Zongker17aa9442009-04-17 10:15:58 -0700741 key, value = line.split("=", 1)
Magnus Strandh63967972019-05-01 23:09:30 +0200742 if (key.startswith("ro.") and
743 key.endswith((".build.fingerprint", ".build.thumbprint"))):
Doug Zongkerc09abc82010-01-11 13:09:15 -0800744 pieces = value.split("/")
745 pieces[-1] = EditTags(pieces[-1])
746 value = "/".join(pieces)
Tao Baocb7ff772015-09-11 15:27:56 -0700747 elif key == "ro.bootimage.build.fingerprint":
748 pieces = value.split("/")
749 pieces[-1] = EditTags(pieces[-1])
750 value = "/".join(pieces)
Doug Zongker17aa9442009-04-17 10:15:58 -0700751 elif key == "ro.build.description":
Doug Zongkerc09abc82010-01-11 13:09:15 -0800752 pieces = value.split(" ")
Doug Zongker17aa9442009-04-17 10:15:58 -0700753 assert len(pieces) == 5
Doug Zongkerc09abc82010-01-11 13:09:15 -0800754 pieces[-1] = EditTags(pieces[-1])
755 value = " ".join(pieces)
Magnus Strandh63967972019-05-01 23:09:30 +0200756 elif key.startswith("ro.") and key.endswith(".build.tags"):
Doug Zongkerc09abc82010-01-11 13:09:15 -0800757 value = EditTags(value)
Doug Zongkera8608a72013-07-23 11:51:04 -0700758 elif key == "ro.build.display.id":
759 # change, eg, "JWR66N dev-keys" to "JWR66N"
760 value = value.split()
Michael Rungedc2661a2014-06-03 14:43:11 -0700761 if len(value) > 1 and value[-1].endswith("-keys"):
Andrew Boie73d5abb2013-12-11 12:42:03 -0800762 value.pop()
763 value = " ".join(value)
Doug Zongkerc09abc82010-01-11 13:09:15 -0800764 line = key + "=" + value
Doug Zongker17aa9442009-04-17 10:15:58 -0700765 if line != original_line:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800766 print(" replace: ", original_line)
767 print(" with: ", line)
Doug Zongker17aa9442009-04-17 10:15:58 -0700768 output.append(line)
769 return "\n".join(output) + "\n"
770
771
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700772def WriteOtacerts(output_zip, filename, keys):
773 """Constructs a zipfile from given keys; and writes it to output_zip.
774
775 Args:
776 output_zip: The output target_files zip.
777 filename: The archive name in the output zip.
778 keys: A list of public keys to use during OTA package verification.
779 """
780
781 try:
782 from StringIO import StringIO
783 except ImportError:
784 from io import StringIO
785 temp_file = StringIO()
786 certs_zip = zipfile.ZipFile(temp_file, "w")
787 for k in keys:
788 common.ZipWrite(certs_zip, k)
789 common.ZipClose(certs_zip)
790 common.ZipWriteStr(output_zip, filename, temp_file.getvalue())
791
792
Doug Zongker831840e2011-09-22 10:28:04 -0700793def ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info):
Doug Zongker8e931bf2009-04-06 15:21:45 -0700794 try:
795 keylist = input_tf_zip.read("META/otakeys.txt").split()
796 except KeyError:
T.R. Fullharta28acc62013-03-18 10:31:26 -0700797 raise common.ExternalError("can't read META/otakeys.txt from input")
Doug Zongker8e931bf2009-04-06 15:21:45 -0700798
Tao Baof718f902017-11-09 10:10:10 -0800799 extra_recovery_keys = misc_info.get("extra_recovery_keys")
Doug Zongkere121d6a2011-02-01 14:13:52 -0800800 if extra_recovery_keys:
801 extra_recovery_keys = [OPTIONS.key_map.get(k, k) + ".x509.pem"
802 for k in extra_recovery_keys.split()]
803 if extra_recovery_keys:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800804 print("extra recovery-only key(s): " + ", ".join(extra_recovery_keys))
Doug Zongkere121d6a2011-02-01 14:13:52 -0800805 else:
806 extra_recovery_keys = []
807
Doug Zongker8e931bf2009-04-06 15:21:45 -0700808 mapped_keys = []
809 for k in keylist:
810 m = re.match(r"^(.*)\.x509\.pem$", k)
811 if not m:
Doug Zongker412c02f2014-02-13 10:58:24 -0800812 raise common.ExternalError(
813 "can't parse \"%s\" from META/otakeys.txt" % (k,))
Doug Zongker8e931bf2009-04-06 15:21:45 -0700814 k = m.group(1)
815 mapped_keys.append(OPTIONS.key_map.get(k, k) + ".x509.pem")
816
Doug Zongkere05628c2009-08-20 17:38:42 -0700817 if mapped_keys:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800818 print("using:\n ", "\n ".join(mapped_keys))
819 print("for OTA package verification")
Doug Zongkere05628c2009-08-20 17:38:42 -0700820 else:
Doug Zongker831840e2011-09-22 10:28:04 -0700821 devkey = misc_info.get("default_system_dev_certificate",
822 "build/target/product/security/testkey")
Tao Baof718f902017-11-09 10:10:10 -0800823 mapped_devkey = OPTIONS.key_map.get(devkey, devkey)
824 if mapped_devkey != devkey:
825 misc_info["default_system_dev_certificate"] = mapped_devkey
826 mapped_keys.append(mapped_devkey + ".x509.pem")
Tao Baoa80ed222016-06-16 14:41:24 -0700827 print("META/otakeys.txt has no keys; using %s for OTA package"
828 " verification." % (mapped_keys[0],))
Doug Zongker8e931bf2009-04-06 15:21:45 -0700829
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700830 # recovery now uses the same x509.pem version of the keys.
Doug Zongkere121d6a2011-02-01 14:13:52 -0800831 # extra_recovery_keys are used only in recovery.
Tom Cherry2929cad2018-09-20 11:04:37 -0700832 if misc_info.get("recovery_as_boot") == "true":
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700833 recovery_keys_location = "BOOT/RAMDISK/system/etc/security/otacerts.zip"
Tao Baoa80ed222016-06-16 14:41:24 -0700834 else:
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700835 recovery_keys_location = "RECOVERY/RAMDISK/system/etc/security/otacerts.zip"
836
837 WriteOtacerts(output_tf_zip, recovery_keys_location,
838 mapped_keys + extra_recovery_keys)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700839
840 # SystemUpdateActivity uses the x509.pem version of the keys, but
841 # put into a zipfile system/etc/security/otacerts.zip.
Doug Zongkere121d6a2011-02-01 14:13:52 -0800842 # We DO NOT include the extra_recovery_keys (if any) here.
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700843 WriteOtacerts(output_tf_zip, "SYSTEM/etc/security/otacerts.zip", mapped_keys)
Doug Zongkereef39442009-04-02 12:14:19 -0700844
Tao Baoa80ed222016-06-16 14:41:24 -0700845 # For A/B devices, update the payload verification key.
846 if misc_info.get("ab_update") == "true":
847 # Unlike otacerts.zip that may contain multiple keys, we can only specify
848 # ONE payload verification key.
849 if len(mapped_keys) > 1:
850 print("\n WARNING: Found more than one OTA keys; Using the first one"
851 " as payload verification key.\n\n")
852
Tao Bao0c28d2d2017-12-24 10:37:38 -0800853 print("Using %s for payload verification." % (mapped_keys[0],))
Tao Bao04e1f012018-02-04 12:13:35 -0800854 pubkey = common.ExtractPublicKey(mapped_keys[0])
Tao Bao13b69622016-07-06 15:28:59 -0700855 common.ZipWriteStr(
Tao Baoa80ed222016-06-16 14:41:24 -0700856 output_tf_zip,
Tao Bao13b69622016-07-06 15:28:59 -0700857 "SYSTEM/etc/update_engine/update-payload-key.pub.pem",
858 pubkey)
Alex Deymob3e8ce62016-08-04 16:06:12 -0700859 common.ZipWriteStr(
860 output_tf_zip,
Tao Bao696bb332018-08-17 16:27:01 -0700861 "BOOT/RAMDISK/system/etc/update_engine/update-payload-key.pub.pem",
Alex Deymob3e8ce62016-08-04 16:06:12 -0700862 pubkey)
Tao Baoa80ed222016-06-16 14:41:24 -0700863
Tao Bao8adcfd12016-06-17 17:01:22 -0700864
Tao Bao0c28d2d2017-12-24 10:37:38 -0800865def ReplaceVerityPublicKey(output_zip, filename, key_path):
866 """Replaces the verity public key at the given path in the given zip.
867
868 Args:
869 output_zip: The output target_files zip.
870 filename: The archive name in the output zip.
871 key_path: The path to the public key.
872 """
873 print("Replacing verity public key with %s" % (key_path,))
874 common.ZipWrite(output_zip, key_path, arcname=filename)
Geremy Condraf19b3652014-07-29 17:54:54 -0700875
Tao Bao8adcfd12016-06-17 17:01:22 -0700876
Tao Bao46a59992017-06-05 11:55:16 -0700877def ReplaceVerityPrivateKey(misc_info, key_path):
Tao Bao0c28d2d2017-12-24 10:37:38 -0800878 """Replaces the verity private key in misc_info dict.
879
880 Args:
881 misc_info: The info dict.
882 key_path: The path to the private key in PKCS#8 format.
883 """
884 print("Replacing verity private key with %s" % (key_path,))
Andrew Boied083f0b2014-09-15 16:01:07 -0700885 misc_info["verity_key"] = key_path
Doug Zongkereef39442009-04-02 12:14:19 -0700886
Tao Bao8adcfd12016-06-17 17:01:22 -0700887
Tao Baoe838d142017-12-23 23:44:48 -0800888def ReplaceVerityKeyId(input_zip, output_zip, key_path):
889 """Replaces the veritykeyid parameter in BOOT/cmdline.
890
891 Args:
892 input_zip: The input target_files zip, which should be already open.
893 output_zip: The output target_files zip, which should be already open and
894 writable.
895 key_path: The path to the PEM encoded X.509 certificate.
896 """
897 in_cmdline = input_zip.read("BOOT/cmdline")
898 # Copy in_cmdline to output_zip if veritykeyid is not present.
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700899 if "veritykeyid" not in in_cmdline:
Tao Baoe838d142017-12-23 23:44:48 -0800900 common.ZipWriteStr(output_zip, "BOOT/cmdline", in_cmdline)
901 return
902
Tao Bao0c28d2d2017-12-24 10:37:38 -0800903 out_buffer = []
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700904 for param in in_cmdline.split():
Tao Baoe838d142017-12-23 23:44:48 -0800905 if "veritykeyid" not in param:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800906 out_buffer.append(param)
Tao Baoe838d142017-12-23 23:44:48 -0800907 continue
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700908
Tao Baoe838d142017-12-23 23:44:48 -0800909 # Extract keyid using openssl command.
910 p = common.Run(["openssl", "x509", "-in", key_path, "-text"],
Tao Baode1d4792018-02-20 10:05:46 -0800911 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
Tao Baoe838d142017-12-23 23:44:48 -0800912 keyid, stderr = p.communicate()
913 assert p.returncode == 0, "Failed to dump certificate: {}".format(stderr)
914 keyid = re.search(
915 r'keyid:([0-9a-fA-F:]*)', keyid).group(1).replace(':', '').lower()
916 print("Replacing verity keyid with {}".format(keyid))
917 out_buffer.append("veritykeyid=id:%s" % (keyid,))
918
919 out_cmdline = ' '.join(out_buffer).strip() + '\n'
920 common.ZipWriteStr(output_zip, "BOOT/cmdline", out_cmdline)
Tao Bao46a59992017-06-05 11:55:16 -0700921
922
923def ReplaceMiscInfoTxt(input_zip, output_zip, misc_info):
924 """Replaces META/misc_info.txt.
925
926 Only writes back the ones in the original META/misc_info.txt. Because the
927 current in-memory dict contains additional items computed at runtime.
928 """
929 misc_info_old = common.LoadDictionaryFromLines(
930 input_zip.read('META/misc_info.txt').split('\n'))
931 items = []
932 for key in sorted(misc_info):
933 if key in misc_info_old:
934 items.append('%s=%s' % (key, misc_info[key]))
935 common.ZipWriteStr(output_zip, "META/misc_info.txt", '\n'.join(items))
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700936
Tao Bao8adcfd12016-06-17 17:01:22 -0700937
Tao Bao639118f2017-06-19 15:48:02 -0700938def ReplaceAvbSigningKeys(misc_info):
939 """Replaces the AVB signing keys."""
940
941 AVB_FOOTER_ARGS_BY_PARTITION = {
Tao Bao0c28d2d2017-12-24 10:37:38 -0800942 'boot' : 'avb_boot_add_hash_footer_args',
943 'dtbo' : 'avb_dtbo_add_hash_footer_args',
944 'recovery' : 'avb_recovery_add_hash_footer_args',
945 'system' : 'avb_system_add_hashtree_footer_args',
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800946 'system_other' : 'avb_system_other_add_hashtree_footer_args',
Tao Bao0c28d2d2017-12-24 10:37:38 -0800947 'vendor' : 'avb_vendor_add_hashtree_footer_args',
948 'vbmeta' : 'avb_vbmeta_args',
Tao Baod403e7b2019-05-06 12:55:42 -0700949 'vbmeta_system' : 'avb_vbmeta_system_args',
950 'vbmeta_vendor' : 'avb_vbmeta_vendor_args',
Tao Bao639118f2017-06-19 15:48:02 -0700951 }
952
953 def ReplaceAvbPartitionSigningKey(partition):
954 key = OPTIONS.avb_keys.get(partition)
955 if not key:
956 return
957
958 algorithm = OPTIONS.avb_algorithms.get(partition)
959 assert algorithm, 'Missing AVB signing algorithm for %s' % (partition,)
960
Tao Bao0c28d2d2017-12-24 10:37:38 -0800961 print('Replacing AVB signing key for %s with "%s" (%s)' % (
962 partition, key, algorithm))
Tao Bao639118f2017-06-19 15:48:02 -0700963 misc_info['avb_' + partition + '_algorithm'] = algorithm
964 misc_info['avb_' + partition + '_key_path'] = key
965
966 extra_args = OPTIONS.avb_extra_args.get(partition)
967 if extra_args:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800968 print('Setting extra AVB signing args for %s to "%s"' % (
969 partition, extra_args))
Tao Bao639118f2017-06-19 15:48:02 -0700970 args_key = AVB_FOOTER_ARGS_BY_PARTITION[partition]
971 misc_info[args_key] = (misc_info.get(args_key, '') + ' ' + extra_args)
972
973 for partition in AVB_FOOTER_ARGS_BY_PARTITION:
974 ReplaceAvbPartitionSigningKey(partition)
975
976
Doug Zongker831840e2011-09-22 10:28:04 -0700977def BuildKeyMap(misc_info, key_mapping_options):
978 for s, d in key_mapping_options:
979 if s is None: # -d option
980 devkey = misc_info.get("default_system_dev_certificate",
981 "build/target/product/security/testkey")
982 devkeydir = os.path.dirname(devkey)
983
984 OPTIONS.key_map.update({
985 devkeydir + "/testkey": d + "/releasekey",
986 devkeydir + "/devkey": d + "/releasekey",
987 devkeydir + "/media": d + "/media",
988 devkeydir + "/shared": d + "/shared",
989 devkeydir + "/platform": d + "/platform",
990 })
991 else:
992 OPTIONS.key_map[s] = d
993
994
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800995def GetApiLevelAndCodename(input_tf_zip):
996 data = input_tf_zip.read("SYSTEM/build.prop")
997 api_level = None
998 codename = None
999 for line in data.split("\n"):
1000 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001001 if line and line[0] != '#' and "=" in line:
1002 key, value = line.split("=", 1)
1003 key = key.strip()
1004 if key == "ro.build.version.sdk":
1005 api_level = int(value.strip())
1006 elif key == "ro.build.version.codename":
1007 codename = value.strip()
1008
1009 if api_level is None:
1010 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
1011 if codename is None:
1012 raise ValueError("No ro.build.version.codename in SYSTEM/build.prop")
1013
1014 return (api_level, codename)
1015
1016
1017def GetCodenameToApiLevelMap(input_tf_zip):
1018 data = input_tf_zip.read("SYSTEM/build.prop")
1019 api_level = None
1020 codenames = None
1021 for line in data.split("\n"):
1022 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001023 if line and line[0] != '#' and "=" in line:
1024 key, value = line.split("=", 1)
1025 key = key.strip()
1026 if key == "ro.build.version.sdk":
1027 api_level = int(value.strip())
1028 elif key == "ro.build.version.all_codenames":
1029 codenames = value.strip().split(",")
1030
1031 if api_level is None:
1032 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
1033 if codenames is None:
1034 raise ValueError("No ro.build.version.all_codenames in SYSTEM/build.prop")
1035
1036 result = dict()
1037 for codename in codenames:
1038 codename = codename.strip()
Tao Baobadceb22019-03-15 09:33:43 -07001039 if codename:
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001040 result[codename] = api_level
1041 return result
1042
1043
Tao Baoaa7e9932019-03-15 09:37:01 -07001044def ReadApexKeysInfo(tf_zip):
1045 """Parses the APEX keys info from a given target-files zip.
1046
1047 Given a target-files ZipFile, parses the META/apexkeys.txt entry and returns a
1048 dict that contains the mapping from APEX names (e.g. com.android.tzdata) to a
1049 tuple of (payload_key, container_key).
1050
1051 Args:
1052 tf_zip: The input target_files ZipFile (already open).
1053
1054 Returns:
1055 (payload_key, container_key): payload_key contains the path to the payload
1056 signing key; container_key contains the path to the container signing
1057 key.
1058 """
1059 keys = {}
1060 for line in tf_zip.read("META/apexkeys.txt").split("\n"):
1061 line = line.strip()
1062 if not line:
1063 continue
1064 matches = re.match(
1065 r'^name="(?P<NAME>.*)"\s+'
1066 r'public_key="(?P<PAYLOAD_PUBLIC_KEY>.*)"\s+'
1067 r'private_key="(?P<PAYLOAD_PRIVATE_KEY>.*)"\s+'
1068 r'container_certificate="(?P<CONTAINER_CERT>.*)"\s+'
1069 r'container_private_key="(?P<CONTAINER_PRIVATE_KEY>.*)"$',
1070 line)
1071 if not matches:
1072 continue
1073
1074 name = matches.group('NAME')
Tao Baoaa7e9932019-03-15 09:37:01 -07001075 payload_private_key = matches.group("PAYLOAD_PRIVATE_KEY")
1076
1077 def CompareKeys(pubkey, pubkey_suffix, privkey, privkey_suffix):
1078 pubkey_suffix_len = len(pubkey_suffix)
1079 privkey_suffix_len = len(privkey_suffix)
1080 return (pubkey.endswith(pubkey_suffix) and
1081 privkey.endswith(privkey_suffix) and
1082 pubkey[:-pubkey_suffix_len] == privkey[:-privkey_suffix_len])
1083
Tao Bao6d9e3da2019-03-26 12:59:25 -07001084 # Sanity check on the container key names, as we'll carry them without the
1085 # extensions. This doesn't apply to payload keys though, which we will use
1086 # full names only.
Tao Baoaa7e9932019-03-15 09:37:01 -07001087 container_cert = matches.group("CONTAINER_CERT")
1088 container_private_key = matches.group("CONTAINER_PRIVATE_KEY")
Tao Bao548db7d2019-04-24 23:53:42 -07001089 if container_cert == 'PRESIGNED' and container_private_key == 'PRESIGNED':
1090 container_key = 'PRESIGNED'
1091 elif CompareKeys(
Tao Baoaa7e9932019-03-15 09:37:01 -07001092 container_cert, OPTIONS.public_key_suffix,
1093 container_private_key, OPTIONS.private_key_suffix):
Tao Bao548db7d2019-04-24 23:53:42 -07001094 container_key = container_cert[:-len(OPTIONS.public_key_suffix)]
1095 else:
Tao Baoaa7e9932019-03-15 09:37:01 -07001096 raise ValueError("Failed to parse container keys: \n{}".format(line))
1097
Tao Bao548db7d2019-04-24 23:53:42 -07001098 keys[name] = (payload_private_key, container_key)
Tao Baoaa7e9932019-03-15 09:37:01 -07001099
1100 return keys
1101
1102
Doug Zongkereef39442009-04-02 12:14:19 -07001103def main(argv):
1104
Doug Zongker831840e2011-09-22 10:28:04 -07001105 key_mapping_options = []
1106
Doug Zongkereef39442009-04-02 12:14:19 -07001107 def option_handler(o, a):
Doug Zongker05d3dea2009-06-22 11:32:31 -07001108 if o in ("-e", "--extra_apks"):
Doug Zongkereef39442009-04-02 12:14:19 -07001109 names, key = a.split("=")
1110 names = names.split(",")
1111 for n in names:
1112 OPTIONS.extra_apks[n] = key
Tao Baoaa7e9932019-03-15 09:37:01 -07001113 elif o == "--extra_apex_payload_key":
1114 apex_name, key = a.split("=")
1115 OPTIONS.extra_apex_payload_keys[apex_name] = key
Tao Bao93c2a012018-06-19 12:19:35 -07001116 elif o == "--skip_apks_with_path_prefix":
1117 # Sanity check the prefix, which must be in all upper case.
1118 prefix = a.split('/')[0]
1119 if not prefix or prefix != prefix.upper():
1120 raise ValueError("Invalid path prefix '%s'" % (a,))
1121 OPTIONS.skip_apks_with_path_prefix.add(a)
Doug Zongkereef39442009-04-02 12:14:19 -07001122 elif o in ("-d", "--default_key_mappings"):
Doug Zongker831840e2011-09-22 10:28:04 -07001123 key_mapping_options.append((None, a))
Doug Zongkereef39442009-04-02 12:14:19 -07001124 elif o in ("-k", "--key_mapping"):
Doug Zongker831840e2011-09-22 10:28:04 -07001125 key_mapping_options.append(a.split("=", 1))
Doug Zongker8e931bf2009-04-06 15:21:45 -07001126 elif o in ("-o", "--replace_ota_keys"):
1127 OPTIONS.replace_ota_keys = True
Doug Zongkerae877012009-04-21 10:04:51 -07001128 elif o in ("-t", "--tag_changes"):
1129 new = []
1130 for i in a.split(","):
1131 i = i.strip()
1132 if not i or i[0] not in "-+":
1133 raise ValueError("Bad tag change '%s'" % (i,))
1134 new.append(i[0] + i[1:].strip())
1135 OPTIONS.tag_changes = tuple(new)
Geremy Condraf19b3652014-07-29 17:54:54 -07001136 elif o == "--replace_verity_public_key":
1137 OPTIONS.replace_verity_public_key = (True, a)
1138 elif o == "--replace_verity_private_key":
1139 OPTIONS.replace_verity_private_key = (True, a)
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001140 elif o == "--replace_verity_keyid":
1141 OPTIONS.replace_verity_keyid = (True, a)
Tao Bao639118f2017-06-19 15:48:02 -07001142 elif o == "--avb_vbmeta_key":
1143 OPTIONS.avb_keys['vbmeta'] = a
1144 elif o == "--avb_vbmeta_algorithm":
1145 OPTIONS.avb_algorithms['vbmeta'] = a
1146 elif o == "--avb_vbmeta_extra_args":
1147 OPTIONS.avb_extra_args['vbmeta'] = a
1148 elif o == "--avb_boot_key":
1149 OPTIONS.avb_keys['boot'] = a
1150 elif o == "--avb_boot_algorithm":
1151 OPTIONS.avb_algorithms['boot'] = a
1152 elif o == "--avb_boot_extra_args":
1153 OPTIONS.avb_extra_args['boot'] = a
1154 elif o == "--avb_dtbo_key":
1155 OPTIONS.avb_keys['dtbo'] = a
1156 elif o == "--avb_dtbo_algorithm":
1157 OPTIONS.avb_algorithms['dtbo'] = a
1158 elif o == "--avb_dtbo_extra_args":
1159 OPTIONS.avb_extra_args['dtbo'] = a
1160 elif o == "--avb_system_key":
1161 OPTIONS.avb_keys['system'] = a
1162 elif o == "--avb_system_algorithm":
1163 OPTIONS.avb_algorithms['system'] = a
1164 elif o == "--avb_system_extra_args":
1165 OPTIONS.avb_extra_args['system'] = a
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001166 elif o == "--avb_system_other_key":
1167 OPTIONS.avb_keys['system_other'] = a
1168 elif o == "--avb_system_other_algorithm":
1169 OPTIONS.avb_algorithms['system_other'] = a
1170 elif o == "--avb_system_other_extra_args":
1171 OPTIONS.avb_extra_args['system_other'] = a
Tao Bao639118f2017-06-19 15:48:02 -07001172 elif o == "--avb_vendor_key":
1173 OPTIONS.avb_keys['vendor'] = a
1174 elif o == "--avb_vendor_algorithm":
1175 OPTIONS.avb_algorithms['vendor'] = a
1176 elif o == "--avb_vendor_extra_args":
1177 OPTIONS.avb_extra_args['vendor'] = a
Tao Baod403e7b2019-05-06 12:55:42 -07001178 elif o == "--avb_vbmeta_system_key":
1179 OPTIONS.avb_keys['vbmeta_system'] = a
1180 elif o == "--avb_vbmeta_system_algorithm":
1181 OPTIONS.avb_algorithms['vbmeta_system'] = a
1182 elif o == "--avb_vbmeta_system_extra_args":
1183 OPTIONS.avb_extra_args['vbmeta_system'] = a
1184 elif o == "--avb_vbmeta_vendor_key":
1185 OPTIONS.avb_keys['vbmeta_vendor'] = a
1186 elif o == "--avb_vbmeta_vendor_algorithm":
1187 OPTIONS.avb_algorithms['vbmeta_vendor'] = a
1188 elif o == "--avb_vbmeta_vendor_extra_args":
1189 OPTIONS.avb_extra_args['vbmeta_vendor'] = a
Tao Baoaa7e9932019-03-15 09:37:01 -07001190 elif o == "--avb_apex_extra_args":
1191 OPTIONS.avb_extra_args['apex'] = a
Doug Zongkereef39442009-04-02 12:14:19 -07001192 else:
1193 return False
1194 return True
1195
Tao Bao639118f2017-06-19 15:48:02 -07001196 args = common.ParseOptions(
1197 argv, __doc__,
1198 extra_opts="e:d:k:ot:",
1199 extra_long_opts=[
Tao Bao0c28d2d2017-12-24 10:37:38 -08001200 "extra_apks=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001201 "extra_apex_payload_key=",
Tao Bao93c2a012018-06-19 12:19:35 -07001202 "skip_apks_with_path_prefix=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001203 "default_key_mappings=",
1204 "key_mapping=",
1205 "replace_ota_keys",
1206 "tag_changes=",
1207 "replace_verity_public_key=",
1208 "replace_verity_private_key=",
1209 "replace_verity_keyid=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001210 "avb_apex_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001211 "avb_vbmeta_algorithm=",
1212 "avb_vbmeta_key=",
1213 "avb_vbmeta_extra_args=",
1214 "avb_boot_algorithm=",
1215 "avb_boot_key=",
1216 "avb_boot_extra_args=",
1217 "avb_dtbo_algorithm=",
1218 "avb_dtbo_key=",
1219 "avb_dtbo_extra_args=",
1220 "avb_system_algorithm=",
1221 "avb_system_key=",
1222 "avb_system_extra_args=",
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001223 "avb_system_other_algorithm=",
1224 "avb_system_other_key=",
1225 "avb_system_other_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001226 "avb_vendor_algorithm=",
1227 "avb_vendor_key=",
1228 "avb_vendor_extra_args=",
Tao Baod403e7b2019-05-06 12:55:42 -07001229 "avb_vbmeta_system_algorithm=",
1230 "avb_vbmeta_system_key=",
1231 "avb_vbmeta_system_extra_args=",
1232 "avb_vbmeta_vendor_algorithm=",
1233 "avb_vbmeta_vendor_key=",
1234 "avb_vbmeta_vendor_extra_args=",
Tao Bao639118f2017-06-19 15:48:02 -07001235 ],
1236 extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001237
1238 if len(args) != 2:
1239 common.Usage(__doc__)
1240 sys.exit(1)
1241
Tao Baobadceb22019-03-15 09:33:43 -07001242 common.InitLogging()
1243
Doug Zongkereef39442009-04-02 12:14:19 -07001244 input_zip = zipfile.ZipFile(args[0], "r")
Tao Bao2b8f4892017-06-13 12:54:58 -07001245 output_zip = zipfile.ZipFile(args[1], "w",
1246 compression=zipfile.ZIP_DEFLATED,
1247 allowZip64=True)
Doug Zongkereef39442009-04-02 12:14:19 -07001248
Doug Zongker831840e2011-09-22 10:28:04 -07001249 misc_info = common.LoadInfoDict(input_zip)
1250
1251 BuildKeyMap(misc_info, key_mapping_options)
1252
Tao Baoaa7e9932019-03-15 09:37:01 -07001253 apk_keys_info, compressed_extension = common.ReadApkCerts(input_zip)
1254 apk_keys = GetApkCerts(apk_keys_info)
Doug Zongkereb338ef2009-05-20 16:50:49 -07001255
Tao Baoaa7e9932019-03-15 09:37:01 -07001256 apex_keys_info = ReadApexKeysInfo(input_zip)
1257 apex_keys = GetApexKeys(apex_keys_info, apk_keys)
1258
1259 CheckApkAndApexKeysAvailable(
1260 input_zip,
1261 set(apk_keys.keys()) | set(apex_keys.keys()),
Tao Baoe1343992019-03-19 12:24:03 -07001262 compressed_extension,
1263 apex_keys)
Tao Baoaa7e9932019-03-15 09:37:01 -07001264
1265 key_passwords = common.GetKeyPasswords(
1266 set(apk_keys.values()) | set(itertools.chain(*apex_keys.values())))
Tao Bao9aa4b9b2016-09-29 17:53:56 -07001267 platform_api_level, _ = GetApiLevelAndCodename(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001268 codename_to_api_level_map = GetCodenameToApiLevelMap(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001269
Doug Zongker412c02f2014-02-13 10:58:24 -08001270 ProcessTargetFiles(input_zip, output_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -07001271 apk_keys, apex_keys, key_passwords,
1272 platform_api_level, codename_to_api_level_map,
Narayan Kamatha07bf042017-08-14 14:49:21 +01001273 compressed_extension)
Doug Zongker8e931bf2009-04-06 15:21:45 -07001274
Tao Bao2ed665a2015-04-01 11:21:55 -07001275 common.ZipClose(input_zip)
1276 common.ZipClose(output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001277
Tianjie Xub48589a2016-08-03 19:21:52 -07001278 # Skip building userdata.img and cache.img when signing the target files.
Tianjie Xu616fbeb2017-05-23 14:51:02 -07001279 new_args = ["--is_signing"]
1280 # add_img_to_target_files builds the system image from scratch, so the
1281 # recovery patch is guaranteed to be regenerated there.
1282 if OPTIONS.rebuild_recovery:
1283 new_args.append("--rebuild_recovery")
1284 new_args.append(args[1])
Tianjie Xub48589a2016-08-03 19:21:52 -07001285 add_img_to_target_files.main(new_args)
Doug Zongker3c84f562014-07-31 11:06:30 -07001286
Tao Bao0c28d2d2017-12-24 10:37:38 -08001287 print("done.")
Doug Zongkereef39442009-04-02 12:14:19 -07001288
1289
1290if __name__ == '__main__':
1291 try:
1292 main(sys.argv[1:])
Tao Bao0c28d2d2017-12-24 10:37:38 -08001293 except common.ExternalError as e:
1294 print("\n ERROR: %s\n" % (e,))
Doug Zongkereef39442009-04-02 12:14:19 -07001295 sys.exit(1)
Tao Bao639118f2017-06-19 15:48:02 -07001296 finally:
1297 common.Cleanup()