blob: 4cb3a379f77ebdd6e1d54d5f789b0690f3efa3bc [file] [log] [blame]
Doug Zongkereef39442009-04-02 12:14:19 -07001#!/usr/bin/env python
2#
3# Copyright (C) 2008 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17"""
18Signs all the APK files in a target-files zipfile, producing a new
19target-files zip.
20
21Usage: sign_target_files_apks [flags] input_target_files output_target_files
22
Doug Zongkereef39442009-04-02 12:14:19 -070023 -e (--extra_apks) <name,name,...=key>
Tao Baoaa7e9932019-03-15 09:37:01 -070024 Add extra APK/APEX name/key pairs as though they appeared in apkcerts.txt
25 or apexkeys.txt (so mappings specified by -k and -d are applied). Keys
26 specified in -e override any value for that app contained in the
27 apkcerts.txt file, or the container key for an APEX. Option may be
28 repeated to give multiple extra packages.
29
30 --extra_apex_payload_key <name=key>
31 Add a mapping for APEX package name to payload signing key, which will
32 override the default payload signing key in apexkeys.txt. Note that the
33 container key should be overridden via the `--extra_apks` flag above.
34 Option may be repeated for multiple APEXes.
Doug Zongkereef39442009-04-02 12:14:19 -070035
Tao Bao93c2a012018-06-19 12:19:35 -070036 --skip_apks_with_path_prefix <prefix>
37 Skip signing an APK if it has the matching prefix in its path. The prefix
38 should be matching the entry name, which has partition names in upper
39 case, e.g. "VENDOR/app/", or "SYSTEM_OTHER/preloads/". Option may be
40 repeated to give multiple prefixes.
41
Doug Zongkereef39442009-04-02 12:14:19 -070042 -k (--key_mapping) <src_key=dest_key>
43 Add a mapping from the key name as specified in apkcerts.txt (the
44 src_key) to the real key you wish to sign the package with
45 (dest_key). Option may be repeated to give multiple key
46 mappings.
47
48 -d (--default_key_mappings) <dir>
49 Set up the following key mappings:
50
Doug Zongker831840e2011-09-22 10:28:04 -070051 $devkey/devkey ==> $dir/releasekey
52 $devkey/testkey ==> $dir/releasekey
53 $devkey/media ==> $dir/media
54 $devkey/shared ==> $dir/shared
55 $devkey/platform ==> $dir/platform
56
57 where $devkey is the directory part of the value of
58 default_system_dev_certificate from the input target-files's
Dan Willemsen0ab1be62019-04-09 21:35:37 -070059 META/misc_info.txt. (Defaulting to "build/make/target/product/security"
Doug Zongker831840e2011-09-22 10:28:04 -070060 if the value is not present in misc_info.
Doug Zongkereef39442009-04-02 12:14:19 -070061
62 -d and -k options are added to the set of mappings in the order
63 in which they appear on the command line.
Doug Zongker8e931bf2009-04-06 15:21:45 -070064
65 -o (--replace_ota_keys)
Tao Baoa80ed222016-06-16 14:41:24 -070066 Replace the certificate (public key) used by OTA package verification
67 with the ones specified in the input target_files zip (in the
68 META/otakeys.txt file). Key remapping (-k and -d) is performed on the
69 keys. For A/B devices, the payload verification key will be replaced
70 as well. If there're multiple OTA keys, only the first one will be used
71 for payload verification.
Doug Zongker17aa9442009-04-17 10:15:58 -070072
Doug Zongkerae877012009-04-21 10:04:51 -070073 -t (--tag_changes) <+tag>,<-tag>,...
74 Comma-separated list of changes to make to the set of tags (in
75 the last component of the build fingerprint). Prefix each with
76 '+' or '-' to indicate whether that tag should be added or
77 removed. Changes are processed in the order they appear.
Doug Zongker831840e2011-09-22 10:28:04 -070078 Default value is "-test-keys,-dev-keys,+release-keys".
Doug Zongkerae877012009-04-21 10:04:51 -070079
Tao Bao8adcfd12016-06-17 17:01:22 -070080 --replace_verity_private_key <key>
81 Replace the private key used for verity signing. It expects a filename
82 WITHOUT the extension (e.g. verity_key).
83
84 --replace_verity_public_key <key>
85 Replace the certificate (public key) used for verity verification. The
86 key file replaces the one at BOOT/RAMDISK/verity_key (or ROOT/verity_key
87 for devices using system_root_image). It expects the key filename WITH
88 the extension (e.g. verity_key.pub).
89
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -070090 --replace_verity_keyid <path_to_X509_PEM_cert_file>
91 Replace the veritykeyid in BOOT/cmdline of input_target_file_zip
Tao Bao8adcfd12016-06-17 17:01:22 -070092 with keyid of the cert pointed by <path_to_X509_PEM_cert_file>.
Tao Bao639118f2017-06-19 15:48:02 -070093
Tao Baod6085d62019-05-06 12:55:42 -070094 --avb_{boot,system,system_other,vendor,dtbo,vbmeta,vbmeta_system,
95 vbmeta_vendor}_algorithm <algorithm>
96 --avb_{boot,system,system_other,vendor,dtbo,vbmeta,vbmeta_system,
97 vbmeta_vendor}_key <key>
Tao Bao639118f2017-06-19 15:48:02 -070098 Use the specified algorithm (e.g. SHA256_RSA4096) and the key to AVB-sign
99 the specified image. Otherwise it uses the existing values in info dict.
100
Tao Baod6085d62019-05-06 12:55:42 -0700101 --avb_{apex,boot,system,system_other,vendor,dtbo,vbmeta,vbmeta_system,
102 vbmeta_vendor}_extra_args <args>
Tao Bao639118f2017-06-19 15:48:02 -0700103 Specify any additional args that are needed to AVB-sign the image
104 (e.g. "--signing_helper /path/to/helper"). The args will be appended to
105 the existing ones in info dict.
Doug Zongkereef39442009-04-02 12:14:19 -0700106"""
107
Tao Bao0c28d2d2017-12-24 10:37:38 -0800108from __future__ import print_function
Doug Zongkereef39442009-04-02 12:14:19 -0700109
Robert Craig817c5742013-04-19 10:59:22 -0400110import base64
Doug Zongker8e931bf2009-04-06 15:21:45 -0700111import copy
Robert Craig817c5742013-04-19 10:59:22 -0400112import errno
Narayan Kamatha07bf042017-08-14 14:49:21 +0100113import gzip
Tao 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
Tao Baoa3705452019-06-24 15:33:41 -0700157 for apk, cert in certmap.items():
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800158 certmap[apk] = OPTIONS.key_map.get(cert, cert)
159
160 # apply all the -e options, overriding anything in the file
Tao Baoa3705452019-06-24 15:33:41 -0700161 for apk, cert in OPTIONS.extra_apks.items():
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.
Tao Baof98fa102019-04-24 14:51:25 -0700182
183 Raises:
184 AssertionError: On invalid container / payload key overrides.
Tao Baoaa7e9932019-03-15 09:37:01 -0700185 """
186 # Apply all the --extra_apex_payload_key options to override the payload
187 # signing keys in the given keys_info.
188 for apex, key in OPTIONS.extra_apex_payload_keys.items():
Tao Baoe1343992019-03-19 12:24:03 -0700189 if not key:
190 key = 'PRESIGNED'
Tao Bao34223092019-07-11 11:52:52 -0700191 if apex not in keys_info:
192 logger.warning('Failed to find %s in target_files; Ignored', apex)
193 continue
Tao Baoaa7e9932019-03-15 09:37:01 -0700194 keys_info[apex] = (key, keys_info[apex][1])
195
196 # Apply the key remapping to container keys.
197 for apex, (payload_key, container_key) in keys_info.items():
198 keys_info[apex] = (payload_key, key_map.get(container_key, container_key))
199
200 # Apply all the --extra_apks options to override the container keys.
201 for apex, key in OPTIONS.extra_apks.items():
202 # Skip non-APEX containers.
203 if apex not in keys_info:
204 continue
Tao Baoe1343992019-03-19 12:24:03 -0700205 if not key:
206 key = 'PRESIGNED'
Tao Baofa9de0a2019-03-18 10:24:17 -0700207 keys_info[apex] = (keys_info[apex][0], key_map.get(key, key))
Tao Baoaa7e9932019-03-15 09:37:01 -0700208
Tao Baof98fa102019-04-24 14:51:25 -0700209 # A PRESIGNED container entails a PRESIGNED payload. Apply this to all the
210 # APEX key pairs. However, a PRESIGNED container with non-PRESIGNED payload
211 # (overridden via commandline) indicates a config error, which should not be
212 # allowed.
213 for apex, (payload_key, container_key) in keys_info.items():
214 if container_key != 'PRESIGNED':
215 continue
216 if apex in OPTIONS.extra_apex_payload_keys:
217 payload_override = OPTIONS.extra_apex_payload_keys[apex]
218 assert payload_override == '', \
219 ("Invalid APEX key overrides: {} has PRESIGNED container but "
220 "non-PRESIGNED payload key {}").format(apex, payload_override)
221 if payload_key != 'PRESIGNED':
222 print(
223 "Setting {} payload as PRESIGNED due to PRESIGNED container".format(
224 apex))
225 keys_info[apex] = ('PRESIGNED', 'PRESIGNED')
226
Tao Baoaa7e9932019-03-15 09:37:01 -0700227 return keys_info
228
229
Tao Bao93c2a012018-06-19 12:19:35 -0700230def GetApkFileInfo(filename, compressed_extension, skipped_prefixes):
Tao Bao11f955c2018-06-19 12:19:35 -0700231 """Returns the APK info based on the given filename.
232
233 Checks if the given filename (with path) looks like an APK file, by taking the
Tao Bao93c2a012018-06-19 12:19:35 -0700234 compressed extension into consideration. If it appears to be an APK file,
235 further checks if the APK file should be skipped when signing, based on the
236 given path prefixes.
Tao Bao11f955c2018-06-19 12:19:35 -0700237
238 Args:
239 filename: Path to the file.
240 compressed_extension: The extension string of compressed APKs (e.g. ".gz"),
241 or None if there's no compressed APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700242 skipped_prefixes: A set/list/tuple of the path prefixes to be skipped.
Tao Bao11f955c2018-06-19 12:19:35 -0700243
244 Returns:
Tao Bao93c2a012018-06-19 12:19:35 -0700245 (is_apk, is_compressed, should_be_skipped): is_apk indicates whether the
246 given filename is an APK file. is_compressed indicates whether the APK file
247 is compressed (only meaningful when is_apk is True). should_be_skipped
248 indicates whether the filename matches any of the given prefixes to be
249 skipped.
Tao Bao11f955c2018-06-19 12:19:35 -0700250
251 Raises:
Tao Bao93c2a012018-06-19 12:19:35 -0700252 AssertionError: On invalid compressed_extension or skipped_prefixes inputs.
Tao Bao11f955c2018-06-19 12:19:35 -0700253 """
254 assert compressed_extension is None or compressed_extension.startswith('.'), \
255 "Invalid compressed_extension arg: '{}'".format(compressed_extension)
256
Tao Bao93c2a012018-06-19 12:19:35 -0700257 # skipped_prefixes should be one of set/list/tuple types. Other types such as
258 # str shouldn't be accepted.
Tao Baobadceb22019-03-15 09:33:43 -0700259 assert isinstance(skipped_prefixes, (set, list, tuple)), \
260 "Invalid skipped_prefixes input type: {}".format(type(skipped_prefixes))
Tao Bao93c2a012018-06-19 12:19:35 -0700261
Tao Bao11f955c2018-06-19 12:19:35 -0700262 compressed_apk_extension = (
263 ".apk" + compressed_extension if compressed_extension else None)
264 is_apk = (filename.endswith(".apk") or
265 (compressed_apk_extension and
266 filename.endswith(compressed_apk_extension)))
267 if not is_apk:
Tao Bao93c2a012018-06-19 12:19:35 -0700268 return (False, False, False)
Tao Bao11f955c2018-06-19 12:19:35 -0700269
270 is_compressed = (compressed_apk_extension and
271 filename.endswith(compressed_apk_extension))
Tao Bao93c2a012018-06-19 12:19:35 -0700272 should_be_skipped = filename.startswith(tuple(skipped_prefixes))
273 return (True, is_compressed, should_be_skipped)
Tao Bao11f955c2018-06-19 12:19:35 -0700274
275
Tao Baoaa7e9932019-03-15 09:37:01 -0700276def CheckApkAndApexKeysAvailable(input_tf_zip, known_keys,
Tao Baoe1343992019-03-19 12:24:03 -0700277 compressed_extension, apex_keys):
Tao Baoaa7e9932019-03-15 09:37:01 -0700278 """Checks that all the APKs and APEXes have keys specified.
Tao Bao11f955c2018-06-19 12:19:35 -0700279
280 Args:
281 input_tf_zip: An open target_files zip file.
Tao Baoaa7e9932019-03-15 09:37:01 -0700282 known_keys: A set of APKs and APEXes that have known signing keys.
Tao Bao11f955c2018-06-19 12:19:35 -0700283 compressed_extension: The extension string of compressed APKs, such as
Tao Baoaa7e9932019-03-15 09:37:01 -0700284 '.gz', or None if there's no compressed APKs.
Tao Baoe1343992019-03-19 12:24:03 -0700285 apex_keys: A dict that contains the key mapping from APEX name to
286 (payload_key, container_key).
Tao Bao11f955c2018-06-19 12:19:35 -0700287
288 Raises:
Tao Baoaa7e9932019-03-15 09:37:01 -0700289 AssertionError: On finding unknown APKs and APEXes.
Tao Bao11f955c2018-06-19 12:19:35 -0700290 """
Tao Baoaa7e9932019-03-15 09:37:01 -0700291 unknown_files = []
Doug Zongkereb338ef2009-05-20 16:50:49 -0700292 for info in input_tf_zip.infolist():
Tao Baoaa7e9932019-03-15 09:37:01 -0700293 # Handle APEXes first, e.g. SYSTEM/apex/com.android.tzdata.apex.
294 if (info.filename.startswith('SYSTEM/apex') and
295 info.filename.endswith('.apex')):
296 name = os.path.basename(info.filename)
297 if name not in known_keys:
298 unknown_files.append(name)
299 continue
300
301 # And APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700302 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
303 info.filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
304 if not is_apk or should_be_skipped:
Tao Bao11f955c2018-06-19 12:19:35 -0700305 continue
Tao Baoaa7e9932019-03-15 09:37:01 -0700306
Tao Bao11f955c2018-06-19 12:19:35 -0700307 name = os.path.basename(info.filename)
308 if is_compressed:
309 name = name[:-len(compressed_extension)]
Tao Baoaa7e9932019-03-15 09:37:01 -0700310 if name not in known_keys:
311 unknown_files.append(name)
Tao Bao11f955c2018-06-19 12:19:35 -0700312
Tao Baoaa7e9932019-03-15 09:37:01 -0700313 assert not unknown_files, \
Tao Bao11f955c2018-06-19 12:19:35 -0700314 ("No key specified for:\n {}\n"
315 "Use '-e <apkname>=' to specify a key (which may be an empty string to "
Tao Baoaa7e9932019-03-15 09:37:01 -0700316 "not sign this apk).".format("\n ".join(unknown_files)))
Doug Zongkereb338ef2009-05-20 16:50:49 -0700317
Tao Baoe1343992019-03-19 12:24:03 -0700318 # For all the APEXes, double check that we won't have an APEX that has only
Tao Baof98fa102019-04-24 14:51:25 -0700319 # one of the payload / container keys set. Note that non-PRESIGNED container
320 # with PRESIGNED payload could be allowed but currently unsupported. It would
321 # require changing SignApex implementation.
Tao Baoe1343992019-03-19 12:24:03 -0700322 if not apex_keys:
323 return
324
325 invalid_apexes = []
326 for info in input_tf_zip.infolist():
327 if (not info.filename.startswith('SYSTEM/apex') or
328 not info.filename.endswith('.apex')):
329 continue
330
331 name = os.path.basename(info.filename)
332 (payload_key, container_key) = apex_keys[name]
333 if ((payload_key in common.SPECIAL_CERT_STRINGS and
334 container_key not in common.SPECIAL_CERT_STRINGS) or
335 (payload_key not in common.SPECIAL_CERT_STRINGS and
336 container_key in common.SPECIAL_CERT_STRINGS)):
337 invalid_apexes.append(
338 "{}: payload_key {}, container_key {}".format(
339 name, payload_key, container_key))
340
341 assert not invalid_apexes, \
342 "Invalid APEX keys specified:\n {}\n".format(
343 "\n ".join(invalid_apexes))
344
Doug Zongkereb338ef2009-05-20 16:50:49 -0700345
Narayan Kamatha07bf042017-08-14 14:49:21 +0100346def SignApk(data, keyname, pw, platform_api_level, codename_to_api_level_map,
347 is_compressed):
Doug Zongkereef39442009-04-02 12:14:19 -0700348 unsigned = tempfile.NamedTemporaryFile()
349 unsigned.write(data)
350 unsigned.flush()
351
Narayan Kamatha07bf042017-08-14 14:49:21 +0100352 if is_compressed:
353 uncompressed = tempfile.NamedTemporaryFile()
Tao Bao0c28d2d2017-12-24 10:37:38 -0800354 with gzip.open(unsigned.name, "rb") as in_file, \
355 open(uncompressed.name, "wb") as out_file:
Narayan Kamatha07bf042017-08-14 14:49:21 +0100356 shutil.copyfileobj(in_file, out_file)
357
358 # Finally, close the "unsigned" file (which is gzip compressed), and then
359 # replace it with the uncompressed version.
360 #
361 # TODO(narayan): All this nastiness can be avoided if python 3.2 is in use,
362 # we could just gzip / gunzip in-memory buffers instead.
363 unsigned.close()
364 unsigned = uncompressed
365
Doug Zongkereef39442009-04-02 12:14:19 -0700366 signed = tempfile.NamedTemporaryFile()
367
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800368 # For pre-N builds, don't upgrade to SHA-256 JAR signatures based on the APK's
369 # minSdkVersion to avoid increasing incremental OTA update sizes. If an APK
370 # didn't change, we don't want its signature to change due to the switch
371 # from SHA-1 to SHA-256.
372 # By default, APK signer chooses SHA-256 signatures if the APK's minSdkVersion
373 # is 18 or higher. For pre-N builds we disable this mechanism by pretending
374 # that the APK's minSdkVersion is 1.
375 # For N+ builds, we let APK signer rely on the APK's minSdkVersion to
376 # determine whether to use SHA-256.
377 min_api_level = None
378 if platform_api_level > 23:
379 # Let APK signer choose whether to use SHA-1 or SHA-256, based on the APK's
380 # minSdkVersion attribute
381 min_api_level = None
382 else:
383 # Force APK signer to use SHA-1
384 min_api_level = 1
385
386 common.SignFile(unsigned.name, signed.name, keyname, pw,
Tao Bao0c28d2d2017-12-24 10:37:38 -0800387 min_api_level=min_api_level,
388 codename_to_api_level_map=codename_to_api_level_map)
Doug Zongkereef39442009-04-02 12:14:19 -0700389
Tao Bao0c28d2d2017-12-24 10:37:38 -0800390 data = None
Narayan Kamatha07bf042017-08-14 14:49:21 +0100391 if is_compressed:
392 # Recompress the file after it has been signed.
393 compressed = tempfile.NamedTemporaryFile()
Tao Bao0c28d2d2017-12-24 10:37:38 -0800394 with open(signed.name, "rb") as in_file, \
395 gzip.open(compressed.name, "wb") as out_file:
Narayan Kamatha07bf042017-08-14 14:49:21 +0100396 shutil.copyfileobj(in_file, out_file)
397
398 data = compressed.read()
399 compressed.close()
400 else:
401 data = signed.read()
402
Doug Zongkereef39442009-04-02 12:14:19 -0700403 unsigned.close()
404 signed.close()
405
406 return data
407
408
Doug Zongker412c02f2014-02-13 10:58:24 -0800409def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -0700410 apk_keys, apex_keys, key_passwords,
411 platform_api_level, codename_to_api_level_map,
Narayan Kamatha07bf042017-08-14 14:49:21 +0100412 compressed_extension):
Tao Bao93c2a012018-06-19 12:19:35 -0700413 # maxsize measures the maximum filename length, including the ones to be
414 # skipped.
Tao Bao0c28d2d2017-12-24 10:37:38 -0800415 maxsize = max(
416 [len(os.path.basename(i.filename)) for i in input_tf_zip.infolist()
Tao Bao93c2a012018-06-19 12:19:35 -0700417 if GetApkFileInfo(i.filename, compressed_extension, [])[0]])
Tao Baoa80ed222016-06-16 14:41:24 -0700418 system_root_image = misc_info.get("system_root_image") == "true"
Doug Zongker412c02f2014-02-13 10:58:24 -0800419
Doug Zongkereef39442009-04-02 12:14:19 -0700420 for info in input_tf_zip.infolist():
Tao Bao11f955c2018-06-19 12:19:35 -0700421 filename = info.filename
422 if filename.startswith("IMAGES/"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700423 continue
Doug Zongker3c84f562014-07-31 11:06:30 -0700424
Tao Bao33bf2682019-01-11 12:37:35 -0800425 # Skip split super images, which will be re-generated during signing.
426 if filename.startswith("OTA/") and filename.endswith(".img"):
427 continue
428
Tao Bao11f955c2018-06-19 12:19:35 -0700429 data = input_tf_zip.read(filename)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700430 out_info = copy.copy(info)
Tao Bao93c2a012018-06-19 12:19:35 -0700431 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
432 filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
433
434 if is_apk and should_be_skipped:
435 # Copy skipped APKs verbatim.
436 print(
437 "NOT signing: %s\n"
438 " (skipped due to matching prefix)" % (filename,))
439 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker412c02f2014-02-13 10:58:24 -0800440
Tao Baof2cffbd2015-07-22 12:33:18 -0700441 # Sign APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700442 elif is_apk:
Tao Bao11f955c2018-06-19 12:19:35 -0700443 name = os.path.basename(filename)
Narayan Kamatha07bf042017-08-14 14:49:21 +0100444 if is_compressed:
445 name = name[:-len(compressed_extension)]
446
Tao Baoaa7e9932019-03-15 09:37:01 -0700447 key = apk_keys[name]
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800448 if key not in common.SPECIAL_CERT_STRINGS:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800449 print(" signing: %-*s (%s)" % (maxsize, name, key))
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800450 signed_data = SignApk(data, key, key_passwords[key], platform_api_level,
Tao Bao0c28d2d2017-12-24 10:37:38 -0800451 codename_to_api_level_map, is_compressed)
Tao Bao2ed665a2015-04-01 11:21:55 -0700452 common.ZipWriteStr(output_tf_zip, out_info, signed_data)
Doug Zongkereef39442009-04-02 12:14:19 -0700453 else:
454 # an APK we're not supposed to sign.
Tao Bao93c2a012018-06-19 12:19:35 -0700455 print(
456 "NOT signing: %s\n"
457 " (skipped due to special cert string)" % (name,))
Tao Bao2ed665a2015-04-01 11:21:55 -0700458 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoa80ed222016-06-16 14:41:24 -0700459
Tao Baoaa7e9932019-03-15 09:37:01 -0700460 # Sign bundled APEX files.
461 elif filename.startswith("SYSTEM/apex") and filename.endswith(".apex"):
462 name = os.path.basename(filename)
463 payload_key, container_key = apex_keys[name]
464
Tao Baoe1343992019-03-19 12:24:03 -0700465 # We've asserted not having a case with only one of them PRESIGNED.
466 if (payload_key not in common.SPECIAL_CERT_STRINGS and
467 container_key not in common.SPECIAL_CERT_STRINGS):
468 print(" signing: %-*s container (%s)" % (
469 maxsize, name, container_key))
470 print(" : %-*s payload (%s)" % (
471 maxsize, name, payload_key))
Tao Baoaa7e9932019-03-15 09:37:01 -0700472
Tao Baoe7354ba2019-05-09 16:54:15 -0700473 signed_apex = apex_utils.SignApex(
Tao Bao1ac886e2019-06-26 11:58:22 -0700474 misc_info['avb_avbtool'],
Tao Baoe1343992019-03-19 12:24:03 -0700475 data,
476 payload_key,
477 container_key,
478 key_passwords[container_key],
479 codename_to_api_level_map,
480 OPTIONS.avb_extra_args.get('apex'))
481 common.ZipWrite(output_tf_zip, signed_apex, filename)
Tao Baoaa7e9932019-03-15 09:37:01 -0700482
Tao Baoe1343992019-03-19 12:24:03 -0700483 else:
484 print(
485 "NOT signing: %s\n"
486 " (skipped due to special cert string)" % (name,))
487 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoaa7e9932019-03-15 09:37:01 -0700488
489 # AVB public keys for the installed APEXes, which will be updated later.
490 elif (os.path.dirname(filename) == 'SYSTEM/etc/security/apex' and
491 filename != 'SYSTEM/etc/security/apex/'):
492 continue
493
Tao Baoa80ed222016-06-16 14:41:24 -0700494 # System properties.
Tao Bao338c1b72019-06-21 09:38:24 -0700495 elif filename in (
496 "SYSTEM/build.prop",
497
498 "VENDOR/build.prop",
499 "SYSTEM/vendor/build.prop",
500
501 "ODM/etc/build.prop",
502 "VENDOR/odm/etc/build.prop",
503
504 "PRODUCT/build.prop",
505 "SYSTEM/product/build.prop",
506
Justin Yun6151e3f2019-06-25 15:58:13 +0900507 "SYSTEM_EXT/build.prop",
508 "SYSTEM/system_ext/build.prop",
Tao Bao338c1b72019-06-21 09:38:24 -0700509
510 "SYSTEM/etc/prop.default",
511 "BOOT/RAMDISK/prop.default",
512 "RECOVERY/RAMDISK/prop.default",
513
514 # ROOT/default.prop is a legacy path, but may still exist for upgrading
515 # devices that don't support `property_overrides_split_enabled`.
516 "ROOT/default.prop",
517
518 # RECOVERY/RAMDISK/default.prop is a legacy path, but will always exist
519 # as a symlink in the current code. So it's a no-op here. Keeping the
520 # path here for clarity.
521 "RECOVERY/RAMDISK/default.prop"):
Tao Bao11f955c2018-06-19 12:19:35 -0700522 print("Rewriting %s:" % (filename,))
Hung-ying Tyan7eb6a922017-05-01 21:56:26 +0800523 if stat.S_ISLNK(info.external_attr >> 16):
524 new_data = data
525 else:
Tao Baoa3705452019-06-24 15:33:41 -0700526 new_data = RewriteProps(data.decode())
Tao Bao2ed665a2015-04-01 11:21:55 -0700527 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700528
Tao Bao66472632017-12-04 17:16:36 -0800529 # Replace the certs in *mac_permissions.xml (there could be multiple, such
530 # as {system,vendor}/etc/selinux/{plat,nonplat}_mac_permissions.xml).
Tao Bao11f955c2018-06-19 12:19:35 -0700531 elif filename.endswith("mac_permissions.xml"):
532 print("Rewriting %s with new keys." % (filename,))
Tao Baoa3705452019-06-24 15:33:41 -0700533 new_data = ReplaceCerts(data.decode())
Tao Bao2ed665a2015-04-01 11:21:55 -0700534 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700535
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700536 # Ask add_img_to_target_files to rebuild the recovery patch if needed.
Tao Bao11f955c2018-06-19 12:19:35 -0700537 elif filename in ("SYSTEM/recovery-from-boot.p",
538 "SYSTEM/etc/recovery.img",
539 "SYSTEM/bin/install-recovery.sh"):
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700540 OPTIONS.rebuild_recovery = True
Tao Baoa80ed222016-06-16 14:41:24 -0700541
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700542 # Don't copy OTA certs if we're replacing them.
Tao Bao696bb332018-08-17 16:27:01 -0700543 elif (
544 OPTIONS.replace_ota_keys and
545 filename in (
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700546 "BOOT/RAMDISK/system/etc/security/otacerts.zip",
Tao Bao696bb332018-08-17 16:27:01 -0700547 "BOOT/RAMDISK/system/etc/update_engine/update-payload-key.pub.pem",
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700548 "RECOVERY/RAMDISK/system/etc/security/otacerts.zip",
Tao Bao696bb332018-08-17 16:27:01 -0700549 "SYSTEM/etc/security/otacerts.zip",
550 "SYSTEM/etc/update_engine/update-payload-key.pub.pem")):
Doug Zongker412c02f2014-02-13 10:58:24 -0800551 pass
Tao Baoa80ed222016-06-16 14:41:24 -0700552
Tao Bao46a59992017-06-05 11:55:16 -0700553 # Skip META/misc_info.txt since we will write back the new values later.
Tao Bao11f955c2018-06-19 12:19:35 -0700554 elif filename == "META/misc_info.txt":
Geremy Condraf19b3652014-07-29 17:54:54 -0700555 pass
Tao Bao8adcfd12016-06-17 17:01:22 -0700556
557 # Skip verity public key if we will replace it.
Michael Runge947894f2014-10-14 20:58:38 -0700558 elif (OPTIONS.replace_verity_public_key and
Tao Bao11f955c2018-06-19 12:19:35 -0700559 filename in ("BOOT/RAMDISK/verity_key",
560 "ROOT/verity_key")):
Geremy Condraf19b3652014-07-29 17:54:54 -0700561 pass
Tao Baoa80ed222016-06-16 14:41:24 -0700562
Tao Bao8adcfd12016-06-17 17:01:22 -0700563 # Skip verity keyid (for system_root_image use) if we will replace it.
Tao Bao11f955c2018-06-19 12:19:35 -0700564 elif OPTIONS.replace_verity_keyid and filename == "BOOT/cmdline":
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700565 pass
566
Tianjie Xu4f099002016-08-11 18:04:27 -0700567 # Skip the care_map as we will regenerate the system/vendor images.
Tianjie Xu4c05f4a2018-09-14 16:24:41 -0700568 elif filename == "META/care_map.pb" or filename == "META/care_map.txt":
Tianjie Xu4f099002016-08-11 18:04:27 -0700569 pass
570
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800571 # Updates system_other.avbpubkey in /product/etc/.
572 elif filename in (
573 "PRODUCT/etc/security/avb/system_other.avbpubkey",
574 "SYSTEM/product/etc/security/avb/system_other.avbpubkey"):
575 # Only update system_other's public key, if the corresponding signing
576 # key is specified via --avb_system_other_key.
577 signing_key = OPTIONS.avb_keys.get("system_other")
578 if signing_key:
Tao Bao1ac886e2019-06-26 11:58:22 -0700579 public_key = common.ExtractAvbPublicKey(
580 misc_info['avb_avbtool'], signing_key)
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800581 print(" Rewriting AVB public key of system_other in /product")
582 common.ZipWrite(output_tf_zip, public_key, filename)
583
Bowgo Tsai78369eb2019-04-23 12:28:44 +0800584 # Should NOT sign boot-debug.img.
585 elif filename in (
586 "BOOT/RAMDISK/force_debuggable",
587 "RECOVERY/RAMDISK/force_debuggable"
588 "RECOVERY/RAMDISK/first_stage_ramdisk/force_debuggable"):
589 raise common.ExternalError("debuggable boot.img cannot be signed")
590
Tao Baoa80ed222016-06-16 14:41:24 -0700591 # A non-APK file; copy it verbatim.
Doug Zongkereef39442009-04-02 12:14:19 -0700592 else:
Tao Bao2ed665a2015-04-01 11:21:55 -0700593 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700594
Doug Zongker412c02f2014-02-13 10:58:24 -0800595 if OPTIONS.replace_ota_keys:
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700596 ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info)
Doug Zongker412c02f2014-02-13 10:58:24 -0800597
Tao Bao46a59992017-06-05 11:55:16 -0700598 # Replace the keyid string in misc_info dict.
Tao Bao8adcfd12016-06-17 17:01:22 -0700599 if OPTIONS.replace_verity_private_key:
Tao Bao46a59992017-06-05 11:55:16 -0700600 ReplaceVerityPrivateKey(misc_info, OPTIONS.replace_verity_private_key[1])
Tao Bao8adcfd12016-06-17 17:01:22 -0700601
602 if OPTIONS.replace_verity_public_key:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800603 dest = "ROOT/verity_key" if system_root_image else "BOOT/RAMDISK/verity_key"
Tao Bao8adcfd12016-06-17 17:01:22 -0700604 # We are replacing the one in boot image only, since the one under
605 # recovery won't ever be needed.
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700606 ReplaceVerityPublicKey(
Tao Bao8adcfd12016-06-17 17:01:22 -0700607 output_tf_zip, dest, OPTIONS.replace_verity_public_key[1])
Tao Bao8adcfd12016-06-17 17:01:22 -0700608
609 # Replace the keyid string in BOOT/cmdline.
610 if OPTIONS.replace_verity_keyid:
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700611 ReplaceVerityKeyId(input_tf_zip, output_tf_zip,
612 OPTIONS.replace_verity_keyid[1])
Doug Zongker412c02f2014-02-13 10:58:24 -0800613
Tao Bao639118f2017-06-19 15:48:02 -0700614 # Replace the AVB signing keys, if any.
615 ReplaceAvbSigningKeys(misc_info)
616
Tao Bao46a59992017-06-05 11:55:16 -0700617 # Write back misc_info with the latest values.
618 ReplaceMiscInfoTxt(input_tf_zip, output_tf_zip, misc_info)
619
Doug Zongker8e931bf2009-04-06 15:21:45 -0700620
Robert Craig817c5742013-04-19 10:59:22 -0400621def ReplaceCerts(data):
Tao Bao66472632017-12-04 17:16:36 -0800622 """Replaces all the occurences of X.509 certs with the new ones.
Robert Craig817c5742013-04-19 10:59:22 -0400623
Tao Bao66472632017-12-04 17:16:36 -0800624 The mapping info is read from OPTIONS.key_map. Non-existent certificate will
625 be skipped. After the replacement, it additionally checks for duplicate
626 entries, which would otherwise fail the policy loading code in
627 frameworks/base/services/core/java/com/android/server/pm/SELinuxMMAC.java.
628
629 Args:
630 data: Input string that contains a set of X.509 certs.
631
632 Returns:
633 A string after the replacement.
634
635 Raises:
636 AssertionError: On finding duplicate entries.
637 """
Tao Baoa3705452019-06-24 15:33:41 -0700638 for old, new in OPTIONS.key_map.items():
Tao Bao66472632017-12-04 17:16:36 -0800639 if OPTIONS.verbose:
640 print(" Replacing %s.x509.pem with %s.x509.pem" % (old, new))
641
642 try:
643 with open(old + ".x509.pem") as old_fp:
644 old_cert16 = base64.b16encode(
Tao Baoa3705452019-06-24 15:33:41 -0700645 common.ParseCertificate(old_fp.read())).decode().lower()
Tao Bao66472632017-12-04 17:16:36 -0800646 with open(new + ".x509.pem") as new_fp:
647 new_cert16 = base64.b16encode(
Tao Baoa3705452019-06-24 15:33:41 -0700648 common.ParseCertificate(new_fp.read())).decode().lower()
Tao Bao66472632017-12-04 17:16:36 -0800649 except IOError as e:
650 if OPTIONS.verbose or e.errno != errno.ENOENT:
651 print(" Error accessing %s: %s.\nSkip replacing %s.x509.pem with "
652 "%s.x509.pem." % (e.filename, e.strerror, old, new))
653 continue
654
655 # Only match entire certs.
656 pattern = "\\b" + old_cert16 + "\\b"
657 (data, num) = re.subn(pattern, new_cert16, data, flags=re.IGNORECASE)
658
659 if OPTIONS.verbose:
660 print(" Replaced %d occurence(s) of %s.x509.pem with %s.x509.pem" % (
661 num, old, new))
662
663 # Verify that there're no duplicate entries after the replacement. Note that
664 # it's only checking entries with global seinfo at the moment (i.e. ignoring
665 # the ones with inner packages). (Bug: 69479366)
666 root = ElementTree.fromstring(data)
667 signatures = [signer.attrib['signature'] for signer in root.findall('signer')]
668 assert len(signatures) == len(set(signatures)), \
669 "Found duplicate entries after cert replacement: {}".format(data)
Robert Craig817c5742013-04-19 10:59:22 -0400670
671 return data
672
673
Doug Zongkerc09abc82010-01-11 13:09:15 -0800674def EditTags(tags):
Tao Baoa7054ee2017-12-08 14:42:16 -0800675 """Applies the edits to the tag string as specified in OPTIONS.tag_changes.
676
677 Args:
678 tags: The input string that contains comma-separated tags.
679
680 Returns:
681 The updated tags (comma-separated and sorted).
682 """
Doug Zongkerc09abc82010-01-11 13:09:15 -0800683 tags = set(tags.split(","))
684 for ch in OPTIONS.tag_changes:
685 if ch[0] == "-":
686 tags.discard(ch[1:])
687 elif ch[0] == "+":
688 tags.add(ch[1:])
689 return ",".join(sorted(tags))
690
691
Tao Baoa7054ee2017-12-08 14:42:16 -0800692def RewriteProps(data):
693 """Rewrites the system properties in the given string.
694
695 Each property is expected in 'key=value' format. The properties that contain
696 build tags (i.e. test-keys, dev-keys) will be updated accordingly by calling
697 EditTags().
698
699 Args:
700 data: Input string, separated by newlines.
701
702 Returns:
703 The string with modified properties.
704 """
Doug Zongker17aa9442009-04-17 10:15:58 -0700705 output = []
706 for line in data.split("\n"):
707 line = line.strip()
708 original_line = line
Michael Rungedc2661a2014-06-03 14:43:11 -0700709 if line and line[0] != '#' and "=" in line:
Doug Zongker17aa9442009-04-17 10:15:58 -0700710 key, value = line.split("=", 1)
Magnus Strandh234f4b42019-05-01 23:09:30 +0200711 if (key.startswith("ro.") and
712 key.endswith((".build.fingerprint", ".build.thumbprint"))):
Doug Zongkerc09abc82010-01-11 13:09:15 -0800713 pieces = value.split("/")
714 pieces[-1] = EditTags(pieces[-1])
715 value = "/".join(pieces)
Tao Baocb7ff772015-09-11 15:27:56 -0700716 elif key == "ro.bootimage.build.fingerprint":
717 pieces = value.split("/")
718 pieces[-1] = EditTags(pieces[-1])
719 value = "/".join(pieces)
Doug Zongker17aa9442009-04-17 10:15:58 -0700720 elif key == "ro.build.description":
Doug Zongkerc09abc82010-01-11 13:09:15 -0800721 pieces = value.split(" ")
Doug Zongker17aa9442009-04-17 10:15:58 -0700722 assert len(pieces) == 5
Doug Zongkerc09abc82010-01-11 13:09:15 -0800723 pieces[-1] = EditTags(pieces[-1])
724 value = " ".join(pieces)
Magnus Strandh234f4b42019-05-01 23:09:30 +0200725 elif key.startswith("ro.") and key.endswith(".build.tags"):
Doug Zongkerc09abc82010-01-11 13:09:15 -0800726 value = EditTags(value)
Doug Zongkera8608a72013-07-23 11:51:04 -0700727 elif key == "ro.build.display.id":
728 # change, eg, "JWR66N dev-keys" to "JWR66N"
729 value = value.split()
Michael Rungedc2661a2014-06-03 14:43:11 -0700730 if len(value) > 1 and value[-1].endswith("-keys"):
Andrew Boie73d5abb2013-12-11 12:42:03 -0800731 value.pop()
732 value = " ".join(value)
Doug Zongkerc09abc82010-01-11 13:09:15 -0800733 line = key + "=" + value
Doug Zongker17aa9442009-04-17 10:15:58 -0700734 if line != original_line:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800735 print(" replace: ", original_line)
736 print(" with: ", line)
Doug Zongker17aa9442009-04-17 10:15:58 -0700737 output.append(line)
738 return "\n".join(output) + "\n"
739
740
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700741def WriteOtacerts(output_zip, filename, keys):
742 """Constructs a zipfile from given keys; and writes it to output_zip.
743
744 Args:
745 output_zip: The output target_files zip.
746 filename: The archive name in the output zip.
747 keys: A list of public keys to use during OTA package verification.
748 """
749
750 try:
751 from StringIO import StringIO
752 except ImportError:
753 from io import StringIO
754 temp_file = StringIO()
755 certs_zip = zipfile.ZipFile(temp_file, "w")
756 for k in keys:
757 common.ZipWrite(certs_zip, k)
758 common.ZipClose(certs_zip)
759 common.ZipWriteStr(output_zip, filename, temp_file.getvalue())
760
761
Doug Zongker831840e2011-09-22 10:28:04 -0700762def ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info):
Doug Zongker8e931bf2009-04-06 15:21:45 -0700763 try:
764 keylist = input_tf_zip.read("META/otakeys.txt").split()
765 except KeyError:
T.R. Fullharta28acc62013-03-18 10:31:26 -0700766 raise common.ExternalError("can't read META/otakeys.txt from input")
Doug Zongker8e931bf2009-04-06 15:21:45 -0700767
Tao Baof718f902017-11-09 10:10:10 -0800768 extra_recovery_keys = misc_info.get("extra_recovery_keys")
Doug Zongkere121d6a2011-02-01 14:13:52 -0800769 if extra_recovery_keys:
770 extra_recovery_keys = [OPTIONS.key_map.get(k, k) + ".x509.pem"
771 for k in extra_recovery_keys.split()]
772 if extra_recovery_keys:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800773 print("extra recovery-only key(s): " + ", ".join(extra_recovery_keys))
Doug Zongkere121d6a2011-02-01 14:13:52 -0800774 else:
775 extra_recovery_keys = []
776
Doug Zongker8e931bf2009-04-06 15:21:45 -0700777 mapped_keys = []
778 for k in keylist:
779 m = re.match(r"^(.*)\.x509\.pem$", k)
780 if not m:
Doug Zongker412c02f2014-02-13 10:58:24 -0800781 raise common.ExternalError(
782 "can't parse \"%s\" from META/otakeys.txt" % (k,))
Doug Zongker8e931bf2009-04-06 15:21:45 -0700783 k = m.group(1)
784 mapped_keys.append(OPTIONS.key_map.get(k, k) + ".x509.pem")
785
Doug Zongkere05628c2009-08-20 17:38:42 -0700786 if mapped_keys:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800787 print("using:\n ", "\n ".join(mapped_keys))
788 print("for OTA package verification")
Doug Zongkere05628c2009-08-20 17:38:42 -0700789 else:
Doug Zongker831840e2011-09-22 10:28:04 -0700790 devkey = misc_info.get("default_system_dev_certificate",
Dan Willemsen0ab1be62019-04-09 21:35:37 -0700791 "build/make/target/product/security/testkey")
Tao Baof718f902017-11-09 10:10:10 -0800792 mapped_devkey = OPTIONS.key_map.get(devkey, devkey)
793 if mapped_devkey != devkey:
794 misc_info["default_system_dev_certificate"] = mapped_devkey
795 mapped_keys.append(mapped_devkey + ".x509.pem")
Tao Baoa80ed222016-06-16 14:41:24 -0700796 print("META/otakeys.txt has no keys; using %s for OTA package"
797 " verification." % (mapped_keys[0],))
Doug Zongker8e931bf2009-04-06 15:21:45 -0700798
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700799 # recovery now uses the same x509.pem version of the keys.
Doug Zongkere121d6a2011-02-01 14:13:52 -0800800 # extra_recovery_keys are used only in recovery.
Tom Cherry2929cad2018-09-20 11:04:37 -0700801 if misc_info.get("recovery_as_boot") == "true":
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700802 recovery_keys_location = "BOOT/RAMDISK/system/etc/security/otacerts.zip"
Tao Baoa80ed222016-06-16 14:41:24 -0700803 else:
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700804 recovery_keys_location = "RECOVERY/RAMDISK/system/etc/security/otacerts.zip"
805
806 WriteOtacerts(output_tf_zip, recovery_keys_location,
807 mapped_keys + extra_recovery_keys)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700808
809 # SystemUpdateActivity uses the x509.pem version of the keys, but
810 # put into a zipfile system/etc/security/otacerts.zip.
Doug Zongkere121d6a2011-02-01 14:13:52 -0800811 # We DO NOT include the extra_recovery_keys (if any) here.
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700812 WriteOtacerts(output_tf_zip, "SYSTEM/etc/security/otacerts.zip", mapped_keys)
Doug Zongkereef39442009-04-02 12:14:19 -0700813
Tao Baoa80ed222016-06-16 14:41:24 -0700814 # For A/B devices, update the payload verification key.
815 if misc_info.get("ab_update") == "true":
816 # Unlike otacerts.zip that may contain multiple keys, we can only specify
817 # ONE payload verification key.
818 if len(mapped_keys) > 1:
819 print("\n WARNING: Found more than one OTA keys; Using the first one"
820 " as payload verification key.\n\n")
821
Tao Bao0c28d2d2017-12-24 10:37:38 -0800822 print("Using %s for payload verification." % (mapped_keys[0],))
Tao Bao04e1f012018-02-04 12:13:35 -0800823 pubkey = common.ExtractPublicKey(mapped_keys[0])
Tao Bao13b69622016-07-06 15:28:59 -0700824 common.ZipWriteStr(
Tao Baoa80ed222016-06-16 14:41:24 -0700825 output_tf_zip,
Tao Bao13b69622016-07-06 15:28:59 -0700826 "SYSTEM/etc/update_engine/update-payload-key.pub.pem",
827 pubkey)
Alex Deymob3e8ce62016-08-04 16:06:12 -0700828 common.ZipWriteStr(
829 output_tf_zip,
Tao Bao696bb332018-08-17 16:27:01 -0700830 "BOOT/RAMDISK/system/etc/update_engine/update-payload-key.pub.pem",
Alex Deymob3e8ce62016-08-04 16:06:12 -0700831 pubkey)
Tao Baoa80ed222016-06-16 14:41:24 -0700832
Tao Bao8adcfd12016-06-17 17:01:22 -0700833
Tao Bao0c28d2d2017-12-24 10:37:38 -0800834def ReplaceVerityPublicKey(output_zip, filename, key_path):
835 """Replaces the verity public key at the given path in the given zip.
836
837 Args:
838 output_zip: The output target_files zip.
839 filename: The archive name in the output zip.
840 key_path: The path to the public key.
841 """
842 print("Replacing verity public key with %s" % (key_path,))
843 common.ZipWrite(output_zip, key_path, arcname=filename)
Geremy Condraf19b3652014-07-29 17:54:54 -0700844
Tao Bao8adcfd12016-06-17 17:01:22 -0700845
Tao Bao46a59992017-06-05 11:55:16 -0700846def ReplaceVerityPrivateKey(misc_info, key_path):
Tao Bao0c28d2d2017-12-24 10:37:38 -0800847 """Replaces the verity private key in misc_info dict.
848
849 Args:
850 misc_info: The info dict.
851 key_path: The path to the private key in PKCS#8 format.
852 """
853 print("Replacing verity private key with %s" % (key_path,))
Andrew Boied083f0b2014-09-15 16:01:07 -0700854 misc_info["verity_key"] = key_path
Doug Zongkereef39442009-04-02 12:14:19 -0700855
Tao Bao8adcfd12016-06-17 17:01:22 -0700856
Tao Baoe838d142017-12-23 23:44:48 -0800857def ReplaceVerityKeyId(input_zip, output_zip, key_path):
858 """Replaces the veritykeyid parameter in BOOT/cmdline.
859
860 Args:
861 input_zip: The input target_files zip, which should be already open.
862 output_zip: The output target_files zip, which should be already open and
863 writable.
864 key_path: The path to the PEM encoded X.509 certificate.
865 """
Tao Baoa3705452019-06-24 15:33:41 -0700866 in_cmdline = input_zip.read("BOOT/cmdline").decode()
Tao Baoe838d142017-12-23 23:44:48 -0800867 # Copy in_cmdline to output_zip if veritykeyid is not present.
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700868 if "veritykeyid" not in in_cmdline:
Tao Baoe838d142017-12-23 23:44:48 -0800869 common.ZipWriteStr(output_zip, "BOOT/cmdline", in_cmdline)
870 return
871
Tao Bao0c28d2d2017-12-24 10:37:38 -0800872 out_buffer = []
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700873 for param in in_cmdline.split():
Tao Baoe838d142017-12-23 23:44:48 -0800874 if "veritykeyid" not in param:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800875 out_buffer.append(param)
Tao Baoe838d142017-12-23 23:44:48 -0800876 continue
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700877
Tao Baoe838d142017-12-23 23:44:48 -0800878 # Extract keyid using openssl command.
879 p = common.Run(["openssl", "x509", "-in", key_path, "-text"],
Tao Baode1d4792018-02-20 10:05:46 -0800880 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
Tao Baoe838d142017-12-23 23:44:48 -0800881 keyid, stderr = p.communicate()
882 assert p.returncode == 0, "Failed to dump certificate: {}".format(stderr)
883 keyid = re.search(
884 r'keyid:([0-9a-fA-F:]*)', keyid).group(1).replace(':', '').lower()
885 print("Replacing verity keyid with {}".format(keyid))
886 out_buffer.append("veritykeyid=id:%s" % (keyid,))
887
888 out_cmdline = ' '.join(out_buffer).strip() + '\n'
889 common.ZipWriteStr(output_zip, "BOOT/cmdline", out_cmdline)
Tao Bao46a59992017-06-05 11:55:16 -0700890
891
892def ReplaceMiscInfoTxt(input_zip, output_zip, misc_info):
893 """Replaces META/misc_info.txt.
894
895 Only writes back the ones in the original META/misc_info.txt. Because the
896 current in-memory dict contains additional items computed at runtime.
897 """
898 misc_info_old = common.LoadDictionaryFromLines(
Tao Baoa3705452019-06-24 15:33:41 -0700899 input_zip.read('META/misc_info.txt').decode().split('\n'))
Tao Bao46a59992017-06-05 11:55:16 -0700900 items = []
901 for key in sorted(misc_info):
902 if key in misc_info_old:
903 items.append('%s=%s' % (key, misc_info[key]))
904 common.ZipWriteStr(output_zip, "META/misc_info.txt", '\n'.join(items))
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700905
Tao Bao8adcfd12016-06-17 17:01:22 -0700906
Tao Bao639118f2017-06-19 15:48:02 -0700907def ReplaceAvbSigningKeys(misc_info):
908 """Replaces the AVB signing keys."""
909
910 AVB_FOOTER_ARGS_BY_PARTITION = {
Tao Bao0c28d2d2017-12-24 10:37:38 -0800911 'boot' : 'avb_boot_add_hash_footer_args',
912 'dtbo' : 'avb_dtbo_add_hash_footer_args',
913 'recovery' : 'avb_recovery_add_hash_footer_args',
914 'system' : 'avb_system_add_hashtree_footer_args',
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800915 'system_other' : 'avb_system_other_add_hashtree_footer_args',
Tao Bao0c28d2d2017-12-24 10:37:38 -0800916 'vendor' : 'avb_vendor_add_hashtree_footer_args',
917 'vbmeta' : 'avb_vbmeta_args',
Tao Baod6085d62019-05-06 12:55:42 -0700918 'vbmeta_system' : 'avb_vbmeta_system_args',
919 'vbmeta_vendor' : 'avb_vbmeta_vendor_args',
Tao Bao639118f2017-06-19 15:48:02 -0700920 }
921
922 def ReplaceAvbPartitionSigningKey(partition):
923 key = OPTIONS.avb_keys.get(partition)
924 if not key:
925 return
926
927 algorithm = OPTIONS.avb_algorithms.get(partition)
928 assert algorithm, 'Missing AVB signing algorithm for %s' % (partition,)
929
Tao Bao0c28d2d2017-12-24 10:37:38 -0800930 print('Replacing AVB signing key for %s with "%s" (%s)' % (
931 partition, key, algorithm))
Tao Bao639118f2017-06-19 15:48:02 -0700932 misc_info['avb_' + partition + '_algorithm'] = algorithm
933 misc_info['avb_' + partition + '_key_path'] = key
934
935 extra_args = OPTIONS.avb_extra_args.get(partition)
936 if extra_args:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800937 print('Setting extra AVB signing args for %s to "%s"' % (
938 partition, extra_args))
Tao Bao639118f2017-06-19 15:48:02 -0700939 args_key = AVB_FOOTER_ARGS_BY_PARTITION[partition]
940 misc_info[args_key] = (misc_info.get(args_key, '') + ' ' + extra_args)
941
942 for partition in AVB_FOOTER_ARGS_BY_PARTITION:
943 ReplaceAvbPartitionSigningKey(partition)
944
945
Doug Zongker831840e2011-09-22 10:28:04 -0700946def BuildKeyMap(misc_info, key_mapping_options):
947 for s, d in key_mapping_options:
948 if s is None: # -d option
949 devkey = misc_info.get("default_system_dev_certificate",
Dan Willemsen0ab1be62019-04-09 21:35:37 -0700950 "build/make/target/product/security/testkey")
Doug Zongker831840e2011-09-22 10:28:04 -0700951 devkeydir = os.path.dirname(devkey)
952
953 OPTIONS.key_map.update({
954 devkeydir + "/testkey": d + "/releasekey",
955 devkeydir + "/devkey": d + "/releasekey",
956 devkeydir + "/media": d + "/media",
957 devkeydir + "/shared": d + "/shared",
958 devkeydir + "/platform": d + "/platform",
959 })
960 else:
961 OPTIONS.key_map[s] = d
962
963
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800964def GetApiLevelAndCodename(input_tf_zip):
Tao Baoa3705452019-06-24 15:33:41 -0700965 data = input_tf_zip.read("SYSTEM/build.prop").decode()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800966 api_level = None
967 codename = None
968 for line in data.split("\n"):
969 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800970 if line and line[0] != '#' and "=" in line:
971 key, value = line.split("=", 1)
972 key = key.strip()
973 if key == "ro.build.version.sdk":
974 api_level = int(value.strip())
975 elif key == "ro.build.version.codename":
976 codename = value.strip()
977
978 if api_level is None:
979 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
980 if codename is None:
981 raise ValueError("No ro.build.version.codename in SYSTEM/build.prop")
982
983 return (api_level, codename)
984
985
986def GetCodenameToApiLevelMap(input_tf_zip):
Tao Baoa3705452019-06-24 15:33:41 -0700987 data = input_tf_zip.read("SYSTEM/build.prop").decode()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800988 api_level = None
989 codenames = None
990 for line in data.split("\n"):
991 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800992 if line and line[0] != '#' and "=" in line:
993 key, value = line.split("=", 1)
994 key = key.strip()
995 if key == "ro.build.version.sdk":
996 api_level = int(value.strip())
997 elif key == "ro.build.version.all_codenames":
998 codenames = value.strip().split(",")
999
1000 if api_level is None:
1001 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
1002 if codenames is None:
1003 raise ValueError("No ro.build.version.all_codenames in SYSTEM/build.prop")
1004
Tao Baoa3705452019-06-24 15:33:41 -07001005 result = {}
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001006 for codename in codenames:
1007 codename = codename.strip()
Tao Baobadceb22019-03-15 09:33:43 -07001008 if codename:
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001009 result[codename] = api_level
1010 return result
1011
1012
Tao Baoaa7e9932019-03-15 09:37:01 -07001013def ReadApexKeysInfo(tf_zip):
1014 """Parses the APEX keys info from a given target-files zip.
1015
1016 Given a target-files ZipFile, parses the META/apexkeys.txt entry and returns a
1017 dict that contains the mapping from APEX names (e.g. com.android.tzdata) to a
1018 tuple of (payload_key, container_key).
1019
1020 Args:
1021 tf_zip: The input target_files ZipFile (already open).
1022
1023 Returns:
1024 (payload_key, container_key): payload_key contains the path to the payload
1025 signing key; container_key contains the path to the container signing
1026 key.
1027 """
1028 keys = {}
Tao Baoa3705452019-06-24 15:33:41 -07001029 for line in tf_zip.read('META/apexkeys.txt').decode().split('\n'):
Tao Baoaa7e9932019-03-15 09:37:01 -07001030 line = line.strip()
1031 if not line:
1032 continue
1033 matches = re.match(
1034 r'^name="(?P<NAME>.*)"\s+'
1035 r'public_key="(?P<PAYLOAD_PUBLIC_KEY>.*)"\s+'
1036 r'private_key="(?P<PAYLOAD_PRIVATE_KEY>.*)"\s+'
1037 r'container_certificate="(?P<CONTAINER_CERT>.*)"\s+'
1038 r'container_private_key="(?P<CONTAINER_PRIVATE_KEY>.*)"$',
1039 line)
1040 if not matches:
1041 continue
1042
1043 name = matches.group('NAME')
Tao Baoaa7e9932019-03-15 09:37:01 -07001044 payload_private_key = matches.group("PAYLOAD_PRIVATE_KEY")
1045
1046 def CompareKeys(pubkey, pubkey_suffix, privkey, privkey_suffix):
1047 pubkey_suffix_len = len(pubkey_suffix)
1048 privkey_suffix_len = len(privkey_suffix)
1049 return (pubkey.endswith(pubkey_suffix) and
1050 privkey.endswith(privkey_suffix) and
1051 pubkey[:-pubkey_suffix_len] == privkey[:-privkey_suffix_len])
1052
Tao Bao6d9e3da2019-03-26 12:59:25 -07001053 # Sanity check on the container key names, as we'll carry them without the
1054 # extensions. This doesn't apply to payload keys though, which we will use
1055 # full names only.
Tao Baoaa7e9932019-03-15 09:37:01 -07001056 container_cert = matches.group("CONTAINER_CERT")
1057 container_private_key = matches.group("CONTAINER_PRIVATE_KEY")
Tao Baof454c3a2019-04-24 23:53:42 -07001058 if container_cert == 'PRESIGNED' and container_private_key == 'PRESIGNED':
1059 container_key = 'PRESIGNED'
1060 elif CompareKeys(
Tao Baoaa7e9932019-03-15 09:37:01 -07001061 container_cert, OPTIONS.public_key_suffix,
1062 container_private_key, OPTIONS.private_key_suffix):
Tao Baof454c3a2019-04-24 23:53:42 -07001063 container_key = container_cert[:-len(OPTIONS.public_key_suffix)]
1064 else:
Tao Baoaa7e9932019-03-15 09:37:01 -07001065 raise ValueError("Failed to parse container keys: \n{}".format(line))
1066
Tao Baof454c3a2019-04-24 23:53:42 -07001067 keys[name] = (payload_private_key, container_key)
Tao Baoaa7e9932019-03-15 09:37:01 -07001068
1069 return keys
1070
1071
Doug Zongkereef39442009-04-02 12:14:19 -07001072def main(argv):
1073
Doug Zongker831840e2011-09-22 10:28:04 -07001074 key_mapping_options = []
1075
Doug Zongkereef39442009-04-02 12:14:19 -07001076 def option_handler(o, a):
Doug Zongker05d3dea2009-06-22 11:32:31 -07001077 if o in ("-e", "--extra_apks"):
Doug Zongkereef39442009-04-02 12:14:19 -07001078 names, key = a.split("=")
1079 names = names.split(",")
1080 for n in names:
1081 OPTIONS.extra_apks[n] = key
Tao Baoaa7e9932019-03-15 09:37:01 -07001082 elif o == "--extra_apex_payload_key":
1083 apex_name, key = a.split("=")
1084 OPTIONS.extra_apex_payload_keys[apex_name] = key
Tao Bao93c2a012018-06-19 12:19:35 -07001085 elif o == "--skip_apks_with_path_prefix":
1086 # Sanity check the prefix, which must be in all upper case.
1087 prefix = a.split('/')[0]
1088 if not prefix or prefix != prefix.upper():
1089 raise ValueError("Invalid path prefix '%s'" % (a,))
1090 OPTIONS.skip_apks_with_path_prefix.add(a)
Doug Zongkereef39442009-04-02 12:14:19 -07001091 elif o in ("-d", "--default_key_mappings"):
Doug Zongker831840e2011-09-22 10:28:04 -07001092 key_mapping_options.append((None, a))
Doug Zongkereef39442009-04-02 12:14:19 -07001093 elif o in ("-k", "--key_mapping"):
Doug Zongker831840e2011-09-22 10:28:04 -07001094 key_mapping_options.append(a.split("=", 1))
Doug Zongker8e931bf2009-04-06 15:21:45 -07001095 elif o in ("-o", "--replace_ota_keys"):
1096 OPTIONS.replace_ota_keys = True
Doug Zongkerae877012009-04-21 10:04:51 -07001097 elif o in ("-t", "--tag_changes"):
1098 new = []
1099 for i in a.split(","):
1100 i = i.strip()
1101 if not i or i[0] not in "-+":
1102 raise ValueError("Bad tag change '%s'" % (i,))
1103 new.append(i[0] + i[1:].strip())
1104 OPTIONS.tag_changes = tuple(new)
Geremy Condraf19b3652014-07-29 17:54:54 -07001105 elif o == "--replace_verity_public_key":
1106 OPTIONS.replace_verity_public_key = (True, a)
1107 elif o == "--replace_verity_private_key":
1108 OPTIONS.replace_verity_private_key = (True, a)
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001109 elif o == "--replace_verity_keyid":
1110 OPTIONS.replace_verity_keyid = (True, a)
Tao Bao639118f2017-06-19 15:48:02 -07001111 elif o == "--avb_vbmeta_key":
1112 OPTIONS.avb_keys['vbmeta'] = a
1113 elif o == "--avb_vbmeta_algorithm":
1114 OPTIONS.avb_algorithms['vbmeta'] = a
1115 elif o == "--avb_vbmeta_extra_args":
1116 OPTIONS.avb_extra_args['vbmeta'] = a
1117 elif o == "--avb_boot_key":
1118 OPTIONS.avb_keys['boot'] = a
1119 elif o == "--avb_boot_algorithm":
1120 OPTIONS.avb_algorithms['boot'] = a
1121 elif o == "--avb_boot_extra_args":
1122 OPTIONS.avb_extra_args['boot'] = a
1123 elif o == "--avb_dtbo_key":
1124 OPTIONS.avb_keys['dtbo'] = a
1125 elif o == "--avb_dtbo_algorithm":
1126 OPTIONS.avb_algorithms['dtbo'] = a
1127 elif o == "--avb_dtbo_extra_args":
1128 OPTIONS.avb_extra_args['dtbo'] = a
1129 elif o == "--avb_system_key":
1130 OPTIONS.avb_keys['system'] = a
1131 elif o == "--avb_system_algorithm":
1132 OPTIONS.avb_algorithms['system'] = a
1133 elif o == "--avb_system_extra_args":
1134 OPTIONS.avb_extra_args['system'] = a
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001135 elif o == "--avb_system_other_key":
1136 OPTIONS.avb_keys['system_other'] = a
1137 elif o == "--avb_system_other_algorithm":
1138 OPTIONS.avb_algorithms['system_other'] = a
1139 elif o == "--avb_system_other_extra_args":
1140 OPTIONS.avb_extra_args['system_other'] = a
Tao Bao639118f2017-06-19 15:48:02 -07001141 elif o == "--avb_vendor_key":
1142 OPTIONS.avb_keys['vendor'] = a
1143 elif o == "--avb_vendor_algorithm":
1144 OPTIONS.avb_algorithms['vendor'] = a
1145 elif o == "--avb_vendor_extra_args":
1146 OPTIONS.avb_extra_args['vendor'] = a
Tao Baod6085d62019-05-06 12:55:42 -07001147 elif o == "--avb_vbmeta_system_key":
1148 OPTIONS.avb_keys['vbmeta_system'] = a
1149 elif o == "--avb_vbmeta_system_algorithm":
1150 OPTIONS.avb_algorithms['vbmeta_system'] = a
1151 elif o == "--avb_vbmeta_system_extra_args":
1152 OPTIONS.avb_extra_args['vbmeta_system'] = a
1153 elif o == "--avb_vbmeta_vendor_key":
1154 OPTIONS.avb_keys['vbmeta_vendor'] = a
1155 elif o == "--avb_vbmeta_vendor_algorithm":
1156 OPTIONS.avb_algorithms['vbmeta_vendor'] = a
1157 elif o == "--avb_vbmeta_vendor_extra_args":
1158 OPTIONS.avb_extra_args['vbmeta_vendor'] = a
Tao Baoaa7e9932019-03-15 09:37:01 -07001159 elif o == "--avb_apex_extra_args":
1160 OPTIONS.avb_extra_args['apex'] = a
Doug Zongkereef39442009-04-02 12:14:19 -07001161 else:
1162 return False
1163 return True
1164
Tao Bao639118f2017-06-19 15:48:02 -07001165 args = common.ParseOptions(
1166 argv, __doc__,
1167 extra_opts="e:d:k:ot:",
1168 extra_long_opts=[
Tao Bao0c28d2d2017-12-24 10:37:38 -08001169 "extra_apks=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001170 "extra_apex_payload_key=",
Tao Bao93c2a012018-06-19 12:19:35 -07001171 "skip_apks_with_path_prefix=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001172 "default_key_mappings=",
1173 "key_mapping=",
1174 "replace_ota_keys",
1175 "tag_changes=",
1176 "replace_verity_public_key=",
1177 "replace_verity_private_key=",
1178 "replace_verity_keyid=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001179 "avb_apex_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001180 "avb_vbmeta_algorithm=",
1181 "avb_vbmeta_key=",
1182 "avb_vbmeta_extra_args=",
1183 "avb_boot_algorithm=",
1184 "avb_boot_key=",
1185 "avb_boot_extra_args=",
1186 "avb_dtbo_algorithm=",
1187 "avb_dtbo_key=",
1188 "avb_dtbo_extra_args=",
1189 "avb_system_algorithm=",
1190 "avb_system_key=",
1191 "avb_system_extra_args=",
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001192 "avb_system_other_algorithm=",
1193 "avb_system_other_key=",
1194 "avb_system_other_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001195 "avb_vendor_algorithm=",
1196 "avb_vendor_key=",
1197 "avb_vendor_extra_args=",
Tao Baod6085d62019-05-06 12:55:42 -07001198 "avb_vbmeta_system_algorithm=",
1199 "avb_vbmeta_system_key=",
1200 "avb_vbmeta_system_extra_args=",
1201 "avb_vbmeta_vendor_algorithm=",
1202 "avb_vbmeta_vendor_key=",
1203 "avb_vbmeta_vendor_extra_args=",
Tao Bao639118f2017-06-19 15:48:02 -07001204 ],
1205 extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001206
1207 if len(args) != 2:
1208 common.Usage(__doc__)
1209 sys.exit(1)
1210
Tao Baobadceb22019-03-15 09:33:43 -07001211 common.InitLogging()
1212
Doug Zongkereef39442009-04-02 12:14:19 -07001213 input_zip = zipfile.ZipFile(args[0], "r")
Tao Bao2b8f4892017-06-13 12:54:58 -07001214 output_zip = zipfile.ZipFile(args[1], "w",
1215 compression=zipfile.ZIP_DEFLATED,
1216 allowZip64=True)
Doug Zongkereef39442009-04-02 12:14:19 -07001217
Doug Zongker831840e2011-09-22 10:28:04 -07001218 misc_info = common.LoadInfoDict(input_zip)
1219
1220 BuildKeyMap(misc_info, key_mapping_options)
1221
Tao Baoaa7e9932019-03-15 09:37:01 -07001222 apk_keys_info, compressed_extension = common.ReadApkCerts(input_zip)
1223 apk_keys = GetApkCerts(apk_keys_info)
Doug Zongkereb338ef2009-05-20 16:50:49 -07001224
Tao Baoaa7e9932019-03-15 09:37:01 -07001225 apex_keys_info = ReadApexKeysInfo(input_zip)
1226 apex_keys = GetApexKeys(apex_keys_info, apk_keys)
1227
1228 CheckApkAndApexKeysAvailable(
1229 input_zip,
1230 set(apk_keys.keys()) | set(apex_keys.keys()),
Tao Baoe1343992019-03-19 12:24:03 -07001231 compressed_extension,
1232 apex_keys)
Tao Baoaa7e9932019-03-15 09:37:01 -07001233
1234 key_passwords = common.GetKeyPasswords(
1235 set(apk_keys.values()) | set(itertools.chain(*apex_keys.values())))
Tao Bao9aa4b9b2016-09-29 17:53:56 -07001236 platform_api_level, _ = GetApiLevelAndCodename(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001237 codename_to_api_level_map = GetCodenameToApiLevelMap(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001238
Doug Zongker412c02f2014-02-13 10:58:24 -08001239 ProcessTargetFiles(input_zip, output_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -07001240 apk_keys, apex_keys, key_passwords,
1241 platform_api_level, codename_to_api_level_map,
Narayan Kamatha07bf042017-08-14 14:49:21 +01001242 compressed_extension)
Doug Zongker8e931bf2009-04-06 15:21:45 -07001243
Tao Bao2ed665a2015-04-01 11:21:55 -07001244 common.ZipClose(input_zip)
1245 common.ZipClose(output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001246
Tianjie Xub48589a2016-08-03 19:21:52 -07001247 # Skip building userdata.img and cache.img when signing the target files.
Tianjie Xu616fbeb2017-05-23 14:51:02 -07001248 new_args = ["--is_signing"]
1249 # add_img_to_target_files builds the system image from scratch, so the
1250 # recovery patch is guaranteed to be regenerated there.
1251 if OPTIONS.rebuild_recovery:
1252 new_args.append("--rebuild_recovery")
1253 new_args.append(args[1])
Tianjie Xub48589a2016-08-03 19:21:52 -07001254 add_img_to_target_files.main(new_args)
Doug Zongker3c84f562014-07-31 11:06:30 -07001255
Tao Bao0c28d2d2017-12-24 10:37:38 -08001256 print("done.")
Doug Zongkereef39442009-04-02 12:14:19 -07001257
1258
1259if __name__ == '__main__':
1260 try:
1261 main(sys.argv[1:])
Tao Bao0c28d2d2017-12-24 10:37:38 -08001262 except common.ExternalError as e:
1263 print("\n ERROR: %s\n" % (e,))
Doug Zongkereef39442009-04-02 12:14:19 -07001264 sys.exit(1)
Tao Bao639118f2017-06-19 15:48:02 -07001265 finally:
1266 common.Cleanup()