blob: 756bc8a9231cfb72c894e56ef9c7bf6acab9d53a [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>
24 Add extra APK name/key pairs as though they appeared in
Doug Zongkerad88c7c2009-04-14 12:34:27 -070025 apkcerts.txt (so mappings specified by -k and -d are applied).
26 Keys specified in -e override any value for that app contained
27 in the apkcerts.txt file. Option may be repeated to give
28 multiple extra packages.
Doug Zongkereef39442009-04-02 12:14:19 -070029
30 -k (--key_mapping) <src_key=dest_key>
31 Add a mapping from the key name as specified in apkcerts.txt (the
32 src_key) to the real key you wish to sign the package with
33 (dest_key). Option may be repeated to give multiple key
34 mappings.
35
36 -d (--default_key_mappings) <dir>
37 Set up the following key mappings:
38
Doug Zongker831840e2011-09-22 10:28:04 -070039 $devkey/devkey ==> $dir/releasekey
40 $devkey/testkey ==> $dir/releasekey
41 $devkey/media ==> $dir/media
42 $devkey/shared ==> $dir/shared
43 $devkey/platform ==> $dir/platform
44
45 where $devkey is the directory part of the value of
46 default_system_dev_certificate from the input target-files's
47 META/misc_info.txt. (Defaulting to "build/target/product/security"
48 if the value is not present in misc_info.
Doug Zongkereef39442009-04-02 12:14:19 -070049
50 -d and -k options are added to the set of mappings in the order
51 in which they appear on the command line.
Doug Zongker8e931bf2009-04-06 15:21:45 -070052
53 -o (--replace_ota_keys)
Tao Baoa80ed222016-06-16 14:41:24 -070054 Replace the certificate (public key) used by OTA package verification
55 with the ones specified in the input target_files zip (in the
56 META/otakeys.txt file). Key remapping (-k and -d) is performed on the
57 keys. For A/B devices, the payload verification key will be replaced
58 as well. If there're multiple OTA keys, only the first one will be used
59 for payload verification.
Doug Zongker17aa9442009-04-17 10:15:58 -070060
Doug Zongkerae877012009-04-21 10:04:51 -070061 -t (--tag_changes) <+tag>,<-tag>,...
62 Comma-separated list of changes to make to the set of tags (in
63 the last component of the build fingerprint). Prefix each with
64 '+' or '-' to indicate whether that tag should be added or
65 removed. Changes are processed in the order they appear.
Doug Zongker831840e2011-09-22 10:28:04 -070066 Default value is "-test-keys,-dev-keys,+release-keys".
Doug Zongkerae877012009-04-21 10:04:51 -070067
Tao Bao8adcfd12016-06-17 17:01:22 -070068 --replace_verity_private_key <key>
69 Replace the private key used for verity signing. It expects a filename
70 WITHOUT the extension (e.g. verity_key).
71
72 --replace_verity_public_key <key>
73 Replace the certificate (public key) used for verity verification. The
74 key file replaces the one at BOOT/RAMDISK/verity_key (or ROOT/verity_key
75 for devices using system_root_image). It expects the key filename WITH
76 the extension (e.g. verity_key.pub).
77
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -070078 --replace_verity_keyid <path_to_X509_PEM_cert_file>
79 Replace the veritykeyid in BOOT/cmdline of input_target_file_zip
Tao Bao8adcfd12016-06-17 17:01:22 -070080 with keyid of the cert pointed by <path_to_X509_PEM_cert_file>.
Tao Bao639118f2017-06-19 15:48:02 -070081
82 --avb_{boot,system,vendor,dtbo,vbmeta}_algorithm <algorithm>
83 --avb_{boot,system,vendor,dtbo,vbmeta}_key <key>
84 Use the specified algorithm (e.g. SHA256_RSA4096) and the key to AVB-sign
85 the specified image. Otherwise it uses the existing values in info dict.
86
87 --avb_{boot,system,vendor,dtbo,vbmeta}_extra_args <args>
88 Specify any additional args that are needed to AVB-sign the image
89 (e.g. "--signing_helper /path/to/helper"). The args will be appended to
90 the existing ones in info dict.
Doug Zongkereef39442009-04-02 12:14:19 -070091"""
92
Tao Bao0c28d2d2017-12-24 10:37:38 -080093from __future__ import print_function
Doug Zongkereef39442009-04-02 12:14:19 -070094
Robert Craig817c5742013-04-19 10:59:22 -040095import base64
Doug Zongker8e931bf2009-04-06 15:21:45 -070096import copy
Robert Craig817c5742013-04-19 10:59:22 -040097import errno
Narayan Kamatha07bf042017-08-14 14:49:21 +010098import gzip
Doug Zongkereef39442009-04-02 12:14:19 -070099import os
100import re
Narayan Kamatha07bf042017-08-14 14:49:21 +0100101import shutil
Tao Bao9fdd00f2017-07-12 11:57:05 -0700102import stat
Doug Zongkereef39442009-04-02 12:14:19 -0700103import subprocess
Tao Bao0c28d2d2017-12-24 10:37:38 -0800104import sys
Doug Zongkereef39442009-04-02 12:14:19 -0700105import tempfile
106import zipfile
Tao Bao66472632017-12-04 17:16:36 -0800107from xml.etree import ElementTree
Doug Zongkereef39442009-04-02 12:14:19 -0700108
Doug Zongker3c84f562014-07-31 11:06:30 -0700109import add_img_to_target_files
Doug Zongkereef39442009-04-02 12:14:19 -0700110import common
111
Tao Bao0c28d2d2017-12-24 10:37:38 -0800112
113if sys.hexversion < 0x02070000:
114 print("Python 2.7 or newer is required.", file=sys.stderr)
115 sys.exit(1)
116
117
Doug Zongkereef39442009-04-02 12:14:19 -0700118OPTIONS = common.OPTIONS
119
120OPTIONS.extra_apks = {}
121OPTIONS.key_map = {}
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700122OPTIONS.rebuild_recovery = False
Doug Zongker8e931bf2009-04-06 15:21:45 -0700123OPTIONS.replace_ota_keys = False
Geremy Condraf19b3652014-07-29 17:54:54 -0700124OPTIONS.replace_verity_public_key = False
125OPTIONS.replace_verity_private_key = False
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700126OPTIONS.replace_verity_keyid = False
Doug Zongker831840e2011-09-22 10:28:04 -0700127OPTIONS.tag_changes = ("-test-keys", "-dev-keys", "+release-keys")
Tao Bao639118f2017-06-19 15:48:02 -0700128OPTIONS.avb_keys = {}
129OPTIONS.avb_algorithms = {}
130OPTIONS.avb_extra_args = {}
Doug Zongkereef39442009-04-02 12:14:19 -0700131
Tao Bao0c28d2d2017-12-24 10:37:38 -0800132
Narayan Kamatha07bf042017-08-14 14:49:21 +0100133def GetApkCerts(certmap):
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800134 # apply the key remapping to the contents of the file
135 for apk, cert in certmap.iteritems():
136 certmap[apk] = OPTIONS.key_map.get(cert, cert)
137
138 # apply all the -e options, overriding anything in the file
Doug Zongkerad88c7c2009-04-14 12:34:27 -0700139 for apk, cert in OPTIONS.extra_apks.iteritems():
Doug Zongkerdecf9952009-12-15 17:27:49 -0800140 if not cert:
141 cert = "PRESIGNED"
Doug Zongkerad88c7c2009-04-14 12:34:27 -0700142 certmap[apk] = OPTIONS.key_map.get(cert, cert)
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800143
Doug Zongkereef39442009-04-02 12:14:19 -0700144 return certmap
145
146
Tao Bao11f955c2018-06-19 12:19:35 -0700147def GetApkFileInfo(filename, compressed_extension):
148 """Returns the APK info based on the given filename.
149
150 Checks if the given filename (with path) looks like an APK file, by taking the
151 compressed extension into consideration.
152
153 Args:
154 filename: Path to the file.
155 compressed_extension: The extension string of compressed APKs (e.g. ".gz"),
156 or None if there's no compressed APKs.
157
158 Returns:
159 (is_apk, is_compressed): is_apk indicates whether the given filename is an
160 APK file. is_compressed indicates whether the APK file is compressed (only
161 meaningful when is_apk is True).
162
163 Raises:
164 AssertionError: On invalid compressed_extension input.
165 """
166 assert compressed_extension is None or compressed_extension.startswith('.'), \
167 "Invalid compressed_extension arg: '{}'".format(compressed_extension)
168
169 compressed_apk_extension = (
170 ".apk" + compressed_extension if compressed_extension else None)
171 is_apk = (filename.endswith(".apk") or
172 (compressed_apk_extension and
173 filename.endswith(compressed_apk_extension)))
174 if not is_apk:
175 return (False, False)
176
177 is_compressed = (compressed_apk_extension and
178 filename.endswith(compressed_apk_extension))
179 return (True, is_compressed)
180
181
Narayan Kamatha07bf042017-08-14 14:49:21 +0100182def CheckAllApksSigned(input_tf_zip, apk_key_map, compressed_extension):
Tao Bao11f955c2018-06-19 12:19:35 -0700183 """Checks that all the APKs have keys specified, otherwise errors out.
184
185 Args:
186 input_tf_zip: An open target_files zip file.
187 apk_key_map: A dict of known signing keys key'd by APK names.
188 compressed_extension: The extension string of compressed APKs, such as
189 ".gz", or None if there's no compressed APKs.
190
191 Raises:
192 AssertionError: On finding unknown APKs.
193 """
Doug Zongkereb338ef2009-05-20 16:50:49 -0700194 unknown_apks = []
195 for info in input_tf_zip.infolist():
Tao Bao11f955c2018-06-19 12:19:35 -0700196 (is_apk, is_compressed) = GetApkFileInfo(
197 info.filename, compressed_extension)
198 if not is_apk:
199 continue
200 name = os.path.basename(info.filename)
201 if is_compressed:
202 name = name[:-len(compressed_extension)]
203 if name not in apk_key_map:
204 unknown_apks.append(name)
205
206 assert not unknown_apks, \
207 ("No key specified for:\n {}\n"
208 "Use '-e <apkname>=' to specify a key (which may be an empty string to "
209 "not sign this apk).".format("\n ".join(unknown_apks)))
Doug Zongkereb338ef2009-05-20 16:50:49 -0700210
211
Narayan Kamatha07bf042017-08-14 14:49:21 +0100212def SignApk(data, keyname, pw, platform_api_level, codename_to_api_level_map,
213 is_compressed):
Doug Zongkereef39442009-04-02 12:14:19 -0700214 unsigned = tempfile.NamedTemporaryFile()
215 unsigned.write(data)
216 unsigned.flush()
217
Narayan Kamatha07bf042017-08-14 14:49:21 +0100218 if is_compressed:
219 uncompressed = tempfile.NamedTemporaryFile()
Tao Bao0c28d2d2017-12-24 10:37:38 -0800220 with gzip.open(unsigned.name, "rb") as in_file, \
221 open(uncompressed.name, "wb") as out_file:
Narayan Kamatha07bf042017-08-14 14:49:21 +0100222 shutil.copyfileobj(in_file, out_file)
223
224 # Finally, close the "unsigned" file (which is gzip compressed), and then
225 # replace it with the uncompressed version.
226 #
227 # TODO(narayan): All this nastiness can be avoided if python 3.2 is in use,
228 # we could just gzip / gunzip in-memory buffers instead.
229 unsigned.close()
230 unsigned = uncompressed
231
Doug Zongkereef39442009-04-02 12:14:19 -0700232 signed = tempfile.NamedTemporaryFile()
233
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800234 # For pre-N builds, don't upgrade to SHA-256 JAR signatures based on the APK's
235 # minSdkVersion to avoid increasing incremental OTA update sizes. If an APK
236 # didn't change, we don't want its signature to change due to the switch
237 # from SHA-1 to SHA-256.
238 # By default, APK signer chooses SHA-256 signatures if the APK's minSdkVersion
239 # is 18 or higher. For pre-N builds we disable this mechanism by pretending
240 # that the APK's minSdkVersion is 1.
241 # For N+ builds, we let APK signer rely on the APK's minSdkVersion to
242 # determine whether to use SHA-256.
243 min_api_level = None
244 if platform_api_level > 23:
245 # Let APK signer choose whether to use SHA-1 or SHA-256, based on the APK's
246 # minSdkVersion attribute
247 min_api_level = None
248 else:
249 # Force APK signer to use SHA-1
250 min_api_level = 1
251
252 common.SignFile(unsigned.name, signed.name, keyname, pw,
Tao Bao0c28d2d2017-12-24 10:37:38 -0800253 min_api_level=min_api_level,
254 codename_to_api_level_map=codename_to_api_level_map)
Doug Zongkereef39442009-04-02 12:14:19 -0700255
Tao Bao0c28d2d2017-12-24 10:37:38 -0800256 data = None
Narayan Kamatha07bf042017-08-14 14:49:21 +0100257 if is_compressed:
258 # Recompress the file after it has been signed.
259 compressed = tempfile.NamedTemporaryFile()
Tao Bao0c28d2d2017-12-24 10:37:38 -0800260 with open(signed.name, "rb") as in_file, \
261 gzip.open(compressed.name, "wb") as out_file:
Narayan Kamatha07bf042017-08-14 14:49:21 +0100262 shutil.copyfileobj(in_file, out_file)
263
264 data = compressed.read()
265 compressed.close()
266 else:
267 data = signed.read()
268
Doug Zongkereef39442009-04-02 12:14:19 -0700269 unsigned.close()
270 signed.close()
271
272 return data
273
274
Doug Zongker412c02f2014-02-13 10:58:24 -0800275def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800276 apk_key_map, key_passwords, platform_api_level,
Narayan Kamatha07bf042017-08-14 14:49:21 +0100277 codename_to_api_level_map,
278 compressed_extension):
Tao Bao0c28d2d2017-12-24 10:37:38 -0800279 maxsize = max(
280 [len(os.path.basename(i.filename)) for i in input_tf_zip.infolist()
Tao Bao11f955c2018-06-19 12:19:35 -0700281 if GetApkFileInfo(i.filename, compressed_extension)[0]])
Tao Baoa80ed222016-06-16 14:41:24 -0700282 system_root_image = misc_info.get("system_root_image") == "true"
Doug Zongker412c02f2014-02-13 10:58:24 -0800283
Doug Zongkereef39442009-04-02 12:14:19 -0700284 for info in input_tf_zip.infolist():
Tao Bao11f955c2018-06-19 12:19:35 -0700285 filename = info.filename
286 if filename.startswith("IMAGES/"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700287 continue
Doug Zongker3c84f562014-07-31 11:06:30 -0700288
Tao Bao11f955c2018-06-19 12:19:35 -0700289 data = input_tf_zip.read(filename)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700290 out_info = copy.copy(info)
Tao Bao11f955c2018-06-19 12:19:35 -0700291 (is_apk, is_compressed) = GetApkFileInfo(filename, compressed_extension)
Doug Zongker412c02f2014-02-13 10:58:24 -0800292
Tao Baof2cffbd2015-07-22 12:33:18 -0700293 # Sign APKs.
Tao Bao11f955c2018-06-19 12:19:35 -0700294 if is_apk:
295 name = os.path.basename(filename)
Narayan Kamatha07bf042017-08-14 14:49:21 +0100296 if is_compressed:
297 name = name[:-len(compressed_extension)]
298
Doug Zongker43874f82009-04-14 14:05:15 -0700299 key = apk_key_map[name]
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800300 if key not in common.SPECIAL_CERT_STRINGS:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800301 print(" signing: %-*s (%s)" % (maxsize, name, key))
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800302 signed_data = SignApk(data, key, key_passwords[key], platform_api_level,
Tao Bao0c28d2d2017-12-24 10:37:38 -0800303 codename_to_api_level_map, is_compressed)
Tao Bao2ed665a2015-04-01 11:21:55 -0700304 common.ZipWriteStr(output_tf_zip, out_info, signed_data)
Doug Zongkereef39442009-04-02 12:14:19 -0700305 else:
306 # an APK we're not supposed to sign.
Tao Bao0c28d2d2017-12-24 10:37:38 -0800307 print("NOT signing: %s" % (name,))
Tao Bao2ed665a2015-04-01 11:21:55 -0700308 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoa80ed222016-06-16 14:41:24 -0700309
310 # System properties.
Tao Bao11f955c2018-06-19 12:19:35 -0700311 elif filename in ("SYSTEM/build.prop",
312 "VENDOR/build.prop",
313 "SYSTEM/etc/prop.default",
314 "BOOT/RAMDISK/prop.default",
315 "BOOT/RAMDISK/default.prop", # legacy
316 "ROOT/default.prop", # legacy
317 "RECOVERY/RAMDISK/prop.default",
318 "RECOVERY/RAMDISK/default.prop"): # legacy
319 print("Rewriting %s:" % (filename,))
Hung-ying Tyan7eb6a922017-05-01 21:56:26 +0800320 if stat.S_ISLNK(info.external_attr >> 16):
321 new_data = data
322 else:
Tao Baoa7054ee2017-12-08 14:42:16 -0800323 new_data = RewriteProps(data)
Tao Bao2ed665a2015-04-01 11:21:55 -0700324 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700325
Tao Bao66472632017-12-04 17:16:36 -0800326 # Replace the certs in *mac_permissions.xml (there could be multiple, such
327 # as {system,vendor}/etc/selinux/{plat,nonplat}_mac_permissions.xml).
Tao Bao11f955c2018-06-19 12:19:35 -0700328 elif filename.endswith("mac_permissions.xml"):
329 print("Rewriting %s with new keys." % (filename,))
Robert Craig817c5742013-04-19 10:59:22 -0400330 new_data = ReplaceCerts(data)
Tao Bao2ed665a2015-04-01 11:21:55 -0700331 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700332
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700333 # Ask add_img_to_target_files to rebuild the recovery patch if needed.
Tao Bao11f955c2018-06-19 12:19:35 -0700334 elif filename in ("SYSTEM/recovery-from-boot.p",
335 "SYSTEM/etc/recovery.img",
336 "SYSTEM/bin/install-recovery.sh"):
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700337 OPTIONS.rebuild_recovery = True
Tao Baoa80ed222016-06-16 14:41:24 -0700338
339 # Don't copy OTA keys if we're replacing them.
Doug Zongker412c02f2014-02-13 10:58:24 -0800340 elif (OPTIONS.replace_ota_keys and
Tao Bao11f955c2018-06-19 12:19:35 -0700341 filename in (
Tao Baoa80ed222016-06-16 14:41:24 -0700342 "BOOT/RAMDISK/res/keys",
Alex Deymob3e8ce62016-08-04 16:06:12 -0700343 "BOOT/RAMDISK/etc/update_engine/update-payload-key.pub.pem",
Tao Baoa80ed222016-06-16 14:41:24 -0700344 "RECOVERY/RAMDISK/res/keys",
345 "SYSTEM/etc/security/otacerts.zip",
346 "SYSTEM/etc/update_engine/update-payload-key.pub.pem")):
Doug Zongker412c02f2014-02-13 10:58:24 -0800347 pass
Tao Baoa80ed222016-06-16 14:41:24 -0700348
Tao Bao46a59992017-06-05 11:55:16 -0700349 # Skip META/misc_info.txt since we will write back the new values later.
Tao Bao11f955c2018-06-19 12:19:35 -0700350 elif filename == "META/misc_info.txt":
Geremy Condraf19b3652014-07-29 17:54:54 -0700351 pass
Tao Bao8adcfd12016-06-17 17:01:22 -0700352
353 # Skip verity public key if we will replace it.
Michael Runge947894f2014-10-14 20:58:38 -0700354 elif (OPTIONS.replace_verity_public_key and
Tao Bao11f955c2018-06-19 12:19:35 -0700355 filename in ("BOOT/RAMDISK/verity_key",
356 "ROOT/verity_key")):
Geremy Condraf19b3652014-07-29 17:54:54 -0700357 pass
Tao Baoa80ed222016-06-16 14:41:24 -0700358
Tao Bao8adcfd12016-06-17 17:01:22 -0700359 # Skip verity keyid (for system_root_image use) if we will replace it.
Tao Bao11f955c2018-06-19 12:19:35 -0700360 elif OPTIONS.replace_verity_keyid and filename == "BOOT/cmdline":
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700361 pass
362
Tianjie Xu4f099002016-08-11 18:04:27 -0700363 # Skip the care_map as we will regenerate the system/vendor images.
Tao Bao11f955c2018-06-19 12:19:35 -0700364 elif filename == "META/care_map.txt":
Tianjie Xu4f099002016-08-11 18:04:27 -0700365 pass
366
Tao Baoa80ed222016-06-16 14:41:24 -0700367 # A non-APK file; copy it verbatim.
Doug Zongkereef39442009-04-02 12:14:19 -0700368 else:
Tao Bao2ed665a2015-04-01 11:21:55 -0700369 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700370
Doug Zongker412c02f2014-02-13 10:58:24 -0800371 if OPTIONS.replace_ota_keys:
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700372 ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info)
Doug Zongker412c02f2014-02-13 10:58:24 -0800373
Tao Bao46a59992017-06-05 11:55:16 -0700374 # Replace the keyid string in misc_info dict.
Tao Bao8adcfd12016-06-17 17:01:22 -0700375 if OPTIONS.replace_verity_private_key:
Tao Bao46a59992017-06-05 11:55:16 -0700376 ReplaceVerityPrivateKey(misc_info, OPTIONS.replace_verity_private_key[1])
Tao Bao8adcfd12016-06-17 17:01:22 -0700377
378 if OPTIONS.replace_verity_public_key:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800379 dest = "ROOT/verity_key" if system_root_image else "BOOT/RAMDISK/verity_key"
Tao Bao8adcfd12016-06-17 17:01:22 -0700380 # We are replacing the one in boot image only, since the one under
381 # recovery won't ever be needed.
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700382 ReplaceVerityPublicKey(
Tao Bao8adcfd12016-06-17 17:01:22 -0700383 output_tf_zip, dest, OPTIONS.replace_verity_public_key[1])
Tao Bao8adcfd12016-06-17 17:01:22 -0700384
385 # Replace the keyid string in BOOT/cmdline.
386 if OPTIONS.replace_verity_keyid:
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700387 ReplaceVerityKeyId(input_tf_zip, output_tf_zip,
388 OPTIONS.replace_verity_keyid[1])
Doug Zongker412c02f2014-02-13 10:58:24 -0800389
Tao Bao639118f2017-06-19 15:48:02 -0700390 # Replace the AVB signing keys, if any.
391 ReplaceAvbSigningKeys(misc_info)
392
Tao Bao46a59992017-06-05 11:55:16 -0700393 # Write back misc_info with the latest values.
394 ReplaceMiscInfoTxt(input_tf_zip, output_tf_zip, misc_info)
395
Doug Zongker8e931bf2009-04-06 15:21:45 -0700396
Robert Craig817c5742013-04-19 10:59:22 -0400397def ReplaceCerts(data):
Tao Bao66472632017-12-04 17:16:36 -0800398 """Replaces all the occurences of X.509 certs with the new ones.
Robert Craig817c5742013-04-19 10:59:22 -0400399
Tao Bao66472632017-12-04 17:16:36 -0800400 The mapping info is read from OPTIONS.key_map. Non-existent certificate will
401 be skipped. After the replacement, it additionally checks for duplicate
402 entries, which would otherwise fail the policy loading code in
403 frameworks/base/services/core/java/com/android/server/pm/SELinuxMMAC.java.
404
405 Args:
406 data: Input string that contains a set of X.509 certs.
407
408 Returns:
409 A string after the replacement.
410
411 Raises:
412 AssertionError: On finding duplicate entries.
413 """
414 for old, new in OPTIONS.key_map.iteritems():
415 if OPTIONS.verbose:
416 print(" Replacing %s.x509.pem with %s.x509.pem" % (old, new))
417
418 try:
419 with open(old + ".x509.pem") as old_fp:
420 old_cert16 = base64.b16encode(
421 common.ParseCertificate(old_fp.read())).lower()
422 with open(new + ".x509.pem") as new_fp:
423 new_cert16 = base64.b16encode(
424 common.ParseCertificate(new_fp.read())).lower()
425 except IOError as e:
426 if OPTIONS.verbose or e.errno != errno.ENOENT:
427 print(" Error accessing %s: %s.\nSkip replacing %s.x509.pem with "
428 "%s.x509.pem." % (e.filename, e.strerror, old, new))
429 continue
430
431 # Only match entire certs.
432 pattern = "\\b" + old_cert16 + "\\b"
433 (data, num) = re.subn(pattern, new_cert16, data, flags=re.IGNORECASE)
434
435 if OPTIONS.verbose:
436 print(" Replaced %d occurence(s) of %s.x509.pem with %s.x509.pem" % (
437 num, old, new))
438
439 # Verify that there're no duplicate entries after the replacement. Note that
440 # it's only checking entries with global seinfo at the moment (i.e. ignoring
441 # the ones with inner packages). (Bug: 69479366)
442 root = ElementTree.fromstring(data)
443 signatures = [signer.attrib['signature'] for signer in root.findall('signer')]
444 assert len(signatures) == len(set(signatures)), \
445 "Found duplicate entries after cert replacement: {}".format(data)
Robert Craig817c5742013-04-19 10:59:22 -0400446
447 return data
448
449
Doug Zongkerc09abc82010-01-11 13:09:15 -0800450def EditTags(tags):
Tao Baoa7054ee2017-12-08 14:42:16 -0800451 """Applies the edits to the tag string as specified in OPTIONS.tag_changes.
452
453 Args:
454 tags: The input string that contains comma-separated tags.
455
456 Returns:
457 The updated tags (comma-separated and sorted).
458 """
Doug Zongkerc09abc82010-01-11 13:09:15 -0800459 tags = set(tags.split(","))
460 for ch in OPTIONS.tag_changes:
461 if ch[0] == "-":
462 tags.discard(ch[1:])
463 elif ch[0] == "+":
464 tags.add(ch[1:])
465 return ",".join(sorted(tags))
466
467
Tao Baoa7054ee2017-12-08 14:42:16 -0800468def RewriteProps(data):
469 """Rewrites the system properties in the given string.
470
471 Each property is expected in 'key=value' format. The properties that contain
472 build tags (i.e. test-keys, dev-keys) will be updated accordingly by calling
473 EditTags().
474
475 Args:
476 data: Input string, separated by newlines.
477
478 Returns:
479 The string with modified properties.
480 """
Doug Zongker17aa9442009-04-17 10:15:58 -0700481 output = []
482 for line in data.split("\n"):
483 line = line.strip()
484 original_line = line
Michael Rungedc2661a2014-06-03 14:43:11 -0700485 if line and line[0] != '#' and "=" in line:
Doug Zongker17aa9442009-04-17 10:15:58 -0700486 key, value = line.split("=", 1)
Tao Baoa7054ee2017-12-08 14:42:16 -0800487 if key in ("ro.build.fingerprint", "ro.build.thumbprint",
488 "ro.vendor.build.fingerprint", "ro.vendor.build.thumbprint"):
Doug Zongkerc09abc82010-01-11 13:09:15 -0800489 pieces = value.split("/")
490 pieces[-1] = EditTags(pieces[-1])
491 value = "/".join(pieces)
Tao Baocb7ff772015-09-11 15:27:56 -0700492 elif key == "ro.bootimage.build.fingerprint":
493 pieces = value.split("/")
494 pieces[-1] = EditTags(pieces[-1])
495 value = "/".join(pieces)
Doug Zongker17aa9442009-04-17 10:15:58 -0700496 elif key == "ro.build.description":
Doug Zongkerc09abc82010-01-11 13:09:15 -0800497 pieces = value.split(" ")
Doug Zongker17aa9442009-04-17 10:15:58 -0700498 assert len(pieces) == 5
Doug Zongkerc09abc82010-01-11 13:09:15 -0800499 pieces[-1] = EditTags(pieces[-1])
500 value = " ".join(pieces)
501 elif key == "ro.build.tags":
502 value = EditTags(value)
Doug Zongkera8608a72013-07-23 11:51:04 -0700503 elif key == "ro.build.display.id":
504 # change, eg, "JWR66N dev-keys" to "JWR66N"
505 value = value.split()
Michael Rungedc2661a2014-06-03 14:43:11 -0700506 if len(value) > 1 and value[-1].endswith("-keys"):
Andrew Boie73d5abb2013-12-11 12:42:03 -0800507 value.pop()
508 value = " ".join(value)
Doug Zongkerc09abc82010-01-11 13:09:15 -0800509 line = key + "=" + value
Doug Zongker17aa9442009-04-17 10:15:58 -0700510 if line != original_line:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800511 print(" replace: ", original_line)
512 print(" with: ", line)
Doug Zongker17aa9442009-04-17 10:15:58 -0700513 output.append(line)
514 return "\n".join(output) + "\n"
515
516
Doug Zongker831840e2011-09-22 10:28:04 -0700517def ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info):
Doug Zongker8e931bf2009-04-06 15:21:45 -0700518 try:
519 keylist = input_tf_zip.read("META/otakeys.txt").split()
520 except KeyError:
T.R. Fullharta28acc62013-03-18 10:31:26 -0700521 raise common.ExternalError("can't read META/otakeys.txt from input")
Doug Zongker8e931bf2009-04-06 15:21:45 -0700522
Tao Baof718f902017-11-09 10:10:10 -0800523 extra_recovery_keys = misc_info.get("extra_recovery_keys")
Doug Zongkere121d6a2011-02-01 14:13:52 -0800524 if extra_recovery_keys:
525 extra_recovery_keys = [OPTIONS.key_map.get(k, k) + ".x509.pem"
526 for k in extra_recovery_keys.split()]
527 if extra_recovery_keys:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800528 print("extra recovery-only key(s): " + ", ".join(extra_recovery_keys))
Doug Zongkere121d6a2011-02-01 14:13:52 -0800529 else:
530 extra_recovery_keys = []
531
Doug Zongker8e931bf2009-04-06 15:21:45 -0700532 mapped_keys = []
533 for k in keylist:
534 m = re.match(r"^(.*)\.x509\.pem$", k)
535 if not m:
Doug Zongker412c02f2014-02-13 10:58:24 -0800536 raise common.ExternalError(
537 "can't parse \"%s\" from META/otakeys.txt" % (k,))
Doug Zongker8e931bf2009-04-06 15:21:45 -0700538 k = m.group(1)
539 mapped_keys.append(OPTIONS.key_map.get(k, k) + ".x509.pem")
540
Doug Zongkere05628c2009-08-20 17:38:42 -0700541 if mapped_keys:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800542 print("using:\n ", "\n ".join(mapped_keys))
543 print("for OTA package verification")
Doug Zongkere05628c2009-08-20 17:38:42 -0700544 else:
Doug Zongker831840e2011-09-22 10:28:04 -0700545 devkey = misc_info.get("default_system_dev_certificate",
546 "build/target/product/security/testkey")
Tao Baof718f902017-11-09 10:10:10 -0800547 mapped_devkey = OPTIONS.key_map.get(devkey, devkey)
548 if mapped_devkey != devkey:
549 misc_info["default_system_dev_certificate"] = mapped_devkey
550 mapped_keys.append(mapped_devkey + ".x509.pem")
Tao Baoa80ed222016-06-16 14:41:24 -0700551 print("META/otakeys.txt has no keys; using %s for OTA package"
552 " verification." % (mapped_keys[0],))
Doug Zongker8e931bf2009-04-06 15:21:45 -0700553
554 # recovery uses a version of the key that has been slightly
555 # predigested (by DumpPublicKey.java) and put in res/keys.
Doug Zongkere121d6a2011-02-01 14:13:52 -0800556 # extra_recovery_keys are used only in recovery.
Tao Baoe95540e2016-11-08 12:08:53 -0800557 cmd = ([OPTIONS.java_path] + OPTIONS.java_args +
558 ["-jar",
559 os.path.join(OPTIONS.search_path, "framework", "dumpkey.jar")] +
560 mapped_keys + extra_recovery_keys)
561 p = common.Run(cmd, stdout=subprocess.PIPE)
Doug Zongker412c02f2014-02-13 10:58:24 -0800562 new_recovery_keys, _ = p.communicate()
Doug Zongker8e931bf2009-04-06 15:21:45 -0700563 if p.returncode != 0:
T.R. Fullharta28acc62013-03-18 10:31:26 -0700564 raise common.ExternalError("failed to run dumpkeys")
Tao Baoa80ed222016-06-16 14:41:24 -0700565
566 # system_root_image puts the recovery keys at BOOT/RAMDISK.
567 if misc_info.get("system_root_image") == "true":
568 recovery_keys_location = "BOOT/RAMDISK/res/keys"
569 else:
570 recovery_keys_location = "RECOVERY/RAMDISK/res/keys"
571 common.ZipWriteStr(output_tf_zip, recovery_keys_location, new_recovery_keys)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700572
573 # SystemUpdateActivity uses the x509.pem version of the keys, but
574 # put into a zipfile system/etc/security/otacerts.zip.
Doug Zongkere121d6a2011-02-01 14:13:52 -0800575 # We DO NOT include the extra_recovery_keys (if any) here.
Doug Zongker8e931bf2009-04-06 15:21:45 -0700576
Tao Bao0c28d2d2017-12-24 10:37:38 -0800577 try:
578 from StringIO import StringIO
579 except ImportError:
580 from io import StringIO
581 temp_file = StringIO()
Dan Albert8b72aef2015-03-23 19:13:21 -0700582 certs_zip = zipfile.ZipFile(temp_file, "w")
Doug Zongker8e931bf2009-04-06 15:21:45 -0700583 for k in mapped_keys:
Tao Bao83cd79d2016-04-11 23:05:52 -0700584 common.ZipWrite(certs_zip, k)
585 common.ZipClose(certs_zip)
Doug Zongker048e7ca2009-06-15 14:31:53 -0700586 common.ZipWriteStr(output_tf_zip, "SYSTEM/etc/security/otacerts.zip",
Dan Albert8b72aef2015-03-23 19:13:21 -0700587 temp_file.getvalue())
Doug Zongkereef39442009-04-02 12:14:19 -0700588
Tao Baoa80ed222016-06-16 14:41:24 -0700589 # For A/B devices, update the payload verification key.
590 if misc_info.get("ab_update") == "true":
591 # Unlike otacerts.zip that may contain multiple keys, we can only specify
592 # ONE payload verification key.
593 if len(mapped_keys) > 1:
594 print("\n WARNING: Found more than one OTA keys; Using the first one"
595 " as payload verification key.\n\n")
596
Tao Bao0c28d2d2017-12-24 10:37:38 -0800597 print("Using %s for payload verification." % (mapped_keys[0],))
Tao Bao04e1f012018-02-04 12:13:35 -0800598 pubkey = common.ExtractPublicKey(mapped_keys[0])
Tao Bao13b69622016-07-06 15:28:59 -0700599 common.ZipWriteStr(
Tao Baoa80ed222016-06-16 14:41:24 -0700600 output_tf_zip,
Tao Bao13b69622016-07-06 15:28:59 -0700601 "SYSTEM/etc/update_engine/update-payload-key.pub.pem",
602 pubkey)
Alex Deymob3e8ce62016-08-04 16:06:12 -0700603 common.ZipWriteStr(
604 output_tf_zip,
605 "BOOT/RAMDISK/etc/update_engine/update-payload-key.pub.pem",
606 pubkey)
Tao Baoa80ed222016-06-16 14:41:24 -0700607
Doug Zongker412c02f2014-02-13 10:58:24 -0800608 return new_recovery_keys
609
Tao Bao8adcfd12016-06-17 17:01:22 -0700610
Tao Bao0c28d2d2017-12-24 10:37:38 -0800611def ReplaceVerityPublicKey(output_zip, filename, key_path):
612 """Replaces the verity public key at the given path in the given zip.
613
614 Args:
615 output_zip: The output target_files zip.
616 filename: The archive name in the output zip.
617 key_path: The path to the public key.
618 """
619 print("Replacing verity public key with %s" % (key_path,))
620 common.ZipWrite(output_zip, key_path, arcname=filename)
Geremy Condraf19b3652014-07-29 17:54:54 -0700621
Tao Bao8adcfd12016-06-17 17:01:22 -0700622
Tao Bao46a59992017-06-05 11:55:16 -0700623def ReplaceVerityPrivateKey(misc_info, key_path):
Tao Bao0c28d2d2017-12-24 10:37:38 -0800624 """Replaces the verity private key in misc_info dict.
625
626 Args:
627 misc_info: The info dict.
628 key_path: The path to the private key in PKCS#8 format.
629 """
630 print("Replacing verity private key with %s" % (key_path,))
Andrew Boied083f0b2014-09-15 16:01:07 -0700631 misc_info["verity_key"] = key_path
Doug Zongkereef39442009-04-02 12:14:19 -0700632
Tao Bao8adcfd12016-06-17 17:01:22 -0700633
Tao Baoe838d142017-12-23 23:44:48 -0800634def ReplaceVerityKeyId(input_zip, output_zip, key_path):
635 """Replaces the veritykeyid parameter in BOOT/cmdline.
636
637 Args:
638 input_zip: The input target_files zip, which should be already open.
639 output_zip: The output target_files zip, which should be already open and
640 writable.
641 key_path: The path to the PEM encoded X.509 certificate.
642 """
643 in_cmdline = input_zip.read("BOOT/cmdline")
644 # Copy in_cmdline to output_zip if veritykeyid is not present.
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700645 if "veritykeyid" not in in_cmdline:
Tao Baoe838d142017-12-23 23:44:48 -0800646 common.ZipWriteStr(output_zip, "BOOT/cmdline", in_cmdline)
647 return
648
Tao Bao0c28d2d2017-12-24 10:37:38 -0800649 out_buffer = []
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700650 for param in in_cmdline.split():
Tao Baoe838d142017-12-23 23:44:48 -0800651 if "veritykeyid" not in param:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800652 out_buffer.append(param)
Tao Baoe838d142017-12-23 23:44:48 -0800653 continue
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700654
Tao Baoe838d142017-12-23 23:44:48 -0800655 # Extract keyid using openssl command.
656 p = common.Run(["openssl", "x509", "-in", key_path, "-text"],
Tao Baode1d4792018-02-20 10:05:46 -0800657 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
Tao Baoe838d142017-12-23 23:44:48 -0800658 keyid, stderr = p.communicate()
659 assert p.returncode == 0, "Failed to dump certificate: {}".format(stderr)
660 keyid = re.search(
661 r'keyid:([0-9a-fA-F:]*)', keyid).group(1).replace(':', '').lower()
662 print("Replacing verity keyid with {}".format(keyid))
663 out_buffer.append("veritykeyid=id:%s" % (keyid,))
664
665 out_cmdline = ' '.join(out_buffer).strip() + '\n'
666 common.ZipWriteStr(output_zip, "BOOT/cmdline", out_cmdline)
Tao Bao46a59992017-06-05 11:55:16 -0700667
668
669def ReplaceMiscInfoTxt(input_zip, output_zip, misc_info):
670 """Replaces META/misc_info.txt.
671
672 Only writes back the ones in the original META/misc_info.txt. Because the
673 current in-memory dict contains additional items computed at runtime.
674 """
675 misc_info_old = common.LoadDictionaryFromLines(
676 input_zip.read('META/misc_info.txt').split('\n'))
677 items = []
678 for key in sorted(misc_info):
679 if key in misc_info_old:
680 items.append('%s=%s' % (key, misc_info[key]))
681 common.ZipWriteStr(output_zip, "META/misc_info.txt", '\n'.join(items))
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700682
Tao Bao8adcfd12016-06-17 17:01:22 -0700683
Tao Bao639118f2017-06-19 15:48:02 -0700684def ReplaceAvbSigningKeys(misc_info):
685 """Replaces the AVB signing keys."""
686
687 AVB_FOOTER_ARGS_BY_PARTITION = {
Tao Bao0c28d2d2017-12-24 10:37:38 -0800688 'boot' : 'avb_boot_add_hash_footer_args',
689 'dtbo' : 'avb_dtbo_add_hash_footer_args',
690 'recovery' : 'avb_recovery_add_hash_footer_args',
691 'system' : 'avb_system_add_hashtree_footer_args',
692 'vendor' : 'avb_vendor_add_hashtree_footer_args',
693 'vbmeta' : 'avb_vbmeta_args',
Tao Bao639118f2017-06-19 15:48:02 -0700694 }
695
696 def ReplaceAvbPartitionSigningKey(partition):
697 key = OPTIONS.avb_keys.get(partition)
698 if not key:
699 return
700
701 algorithm = OPTIONS.avb_algorithms.get(partition)
702 assert algorithm, 'Missing AVB signing algorithm for %s' % (partition,)
703
Tao Bao0c28d2d2017-12-24 10:37:38 -0800704 print('Replacing AVB signing key for %s with "%s" (%s)' % (
705 partition, key, algorithm))
Tao Bao639118f2017-06-19 15:48:02 -0700706 misc_info['avb_' + partition + '_algorithm'] = algorithm
707 misc_info['avb_' + partition + '_key_path'] = key
708
709 extra_args = OPTIONS.avb_extra_args.get(partition)
710 if extra_args:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800711 print('Setting extra AVB signing args for %s to "%s"' % (
712 partition, extra_args))
Tao Bao639118f2017-06-19 15:48:02 -0700713 args_key = AVB_FOOTER_ARGS_BY_PARTITION[partition]
714 misc_info[args_key] = (misc_info.get(args_key, '') + ' ' + extra_args)
715
716 for partition in AVB_FOOTER_ARGS_BY_PARTITION:
717 ReplaceAvbPartitionSigningKey(partition)
718
719
Doug Zongker831840e2011-09-22 10:28:04 -0700720def BuildKeyMap(misc_info, key_mapping_options):
721 for s, d in key_mapping_options:
722 if s is None: # -d option
723 devkey = misc_info.get("default_system_dev_certificate",
724 "build/target/product/security/testkey")
725 devkeydir = os.path.dirname(devkey)
726
727 OPTIONS.key_map.update({
728 devkeydir + "/testkey": d + "/releasekey",
729 devkeydir + "/devkey": d + "/releasekey",
730 devkeydir + "/media": d + "/media",
731 devkeydir + "/shared": d + "/shared",
732 devkeydir + "/platform": d + "/platform",
733 })
734 else:
735 OPTIONS.key_map[s] = d
736
737
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800738def GetApiLevelAndCodename(input_tf_zip):
739 data = input_tf_zip.read("SYSTEM/build.prop")
740 api_level = None
741 codename = None
742 for line in data.split("\n"):
743 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800744 if line and line[0] != '#' and "=" in line:
745 key, value = line.split("=", 1)
746 key = key.strip()
747 if key == "ro.build.version.sdk":
748 api_level = int(value.strip())
749 elif key == "ro.build.version.codename":
750 codename = value.strip()
751
752 if api_level is None:
753 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
754 if codename is None:
755 raise ValueError("No ro.build.version.codename in SYSTEM/build.prop")
756
757 return (api_level, codename)
758
759
760def GetCodenameToApiLevelMap(input_tf_zip):
761 data = input_tf_zip.read("SYSTEM/build.prop")
762 api_level = None
763 codenames = None
764 for line in data.split("\n"):
765 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800766 if line and line[0] != '#' and "=" in line:
767 key, value = line.split("=", 1)
768 key = key.strip()
769 if key == "ro.build.version.sdk":
770 api_level = int(value.strip())
771 elif key == "ro.build.version.all_codenames":
772 codenames = value.strip().split(",")
773
774 if api_level is None:
775 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
776 if codenames is None:
777 raise ValueError("No ro.build.version.all_codenames in SYSTEM/build.prop")
778
779 result = dict()
780 for codename in codenames:
781 codename = codename.strip()
782 if len(codename) > 0:
783 result[codename] = api_level
784 return result
785
786
Doug Zongkereef39442009-04-02 12:14:19 -0700787def main(argv):
788
Doug Zongker831840e2011-09-22 10:28:04 -0700789 key_mapping_options = []
790
Doug Zongkereef39442009-04-02 12:14:19 -0700791 def option_handler(o, a):
Doug Zongker05d3dea2009-06-22 11:32:31 -0700792 if o in ("-e", "--extra_apks"):
Doug Zongkereef39442009-04-02 12:14:19 -0700793 names, key = a.split("=")
794 names = names.split(",")
795 for n in names:
796 OPTIONS.extra_apks[n] = key
797 elif o in ("-d", "--default_key_mappings"):
Doug Zongker831840e2011-09-22 10:28:04 -0700798 key_mapping_options.append((None, a))
Doug Zongkereef39442009-04-02 12:14:19 -0700799 elif o in ("-k", "--key_mapping"):
Doug Zongker831840e2011-09-22 10:28:04 -0700800 key_mapping_options.append(a.split("=", 1))
Doug Zongker8e931bf2009-04-06 15:21:45 -0700801 elif o in ("-o", "--replace_ota_keys"):
802 OPTIONS.replace_ota_keys = True
Doug Zongkerae877012009-04-21 10:04:51 -0700803 elif o in ("-t", "--tag_changes"):
804 new = []
805 for i in a.split(","):
806 i = i.strip()
807 if not i or i[0] not in "-+":
808 raise ValueError("Bad tag change '%s'" % (i,))
809 new.append(i[0] + i[1:].strip())
810 OPTIONS.tag_changes = tuple(new)
Geremy Condraf19b3652014-07-29 17:54:54 -0700811 elif o == "--replace_verity_public_key":
812 OPTIONS.replace_verity_public_key = (True, a)
813 elif o == "--replace_verity_private_key":
814 OPTIONS.replace_verity_private_key = (True, a)
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700815 elif o == "--replace_verity_keyid":
816 OPTIONS.replace_verity_keyid = (True, a)
Tao Bao639118f2017-06-19 15:48:02 -0700817 elif o == "--avb_vbmeta_key":
818 OPTIONS.avb_keys['vbmeta'] = a
819 elif o == "--avb_vbmeta_algorithm":
820 OPTIONS.avb_algorithms['vbmeta'] = a
821 elif o == "--avb_vbmeta_extra_args":
822 OPTIONS.avb_extra_args['vbmeta'] = a
823 elif o == "--avb_boot_key":
824 OPTIONS.avb_keys['boot'] = a
825 elif o == "--avb_boot_algorithm":
826 OPTIONS.avb_algorithms['boot'] = a
827 elif o == "--avb_boot_extra_args":
828 OPTIONS.avb_extra_args['boot'] = a
829 elif o == "--avb_dtbo_key":
830 OPTIONS.avb_keys['dtbo'] = a
831 elif o == "--avb_dtbo_algorithm":
832 OPTIONS.avb_algorithms['dtbo'] = a
833 elif o == "--avb_dtbo_extra_args":
834 OPTIONS.avb_extra_args['dtbo'] = a
835 elif o == "--avb_system_key":
836 OPTIONS.avb_keys['system'] = a
837 elif o == "--avb_system_algorithm":
838 OPTIONS.avb_algorithms['system'] = a
839 elif o == "--avb_system_extra_args":
840 OPTIONS.avb_extra_args['system'] = a
841 elif o == "--avb_vendor_key":
842 OPTIONS.avb_keys['vendor'] = a
843 elif o == "--avb_vendor_algorithm":
844 OPTIONS.avb_algorithms['vendor'] = a
845 elif o == "--avb_vendor_extra_args":
846 OPTIONS.avb_extra_args['vendor'] = a
Doug Zongkereef39442009-04-02 12:14:19 -0700847 else:
848 return False
849 return True
850
Tao Bao639118f2017-06-19 15:48:02 -0700851 args = common.ParseOptions(
852 argv, __doc__,
853 extra_opts="e:d:k:ot:",
854 extra_long_opts=[
Tao Bao0c28d2d2017-12-24 10:37:38 -0800855 "extra_apks=",
856 "default_key_mappings=",
857 "key_mapping=",
858 "replace_ota_keys",
859 "tag_changes=",
860 "replace_verity_public_key=",
861 "replace_verity_private_key=",
862 "replace_verity_keyid=",
863 "avb_vbmeta_algorithm=",
864 "avb_vbmeta_key=",
865 "avb_vbmeta_extra_args=",
866 "avb_boot_algorithm=",
867 "avb_boot_key=",
868 "avb_boot_extra_args=",
869 "avb_dtbo_algorithm=",
870 "avb_dtbo_key=",
871 "avb_dtbo_extra_args=",
872 "avb_system_algorithm=",
873 "avb_system_key=",
874 "avb_system_extra_args=",
875 "avb_vendor_algorithm=",
876 "avb_vendor_key=",
877 "avb_vendor_extra_args=",
Tao Bao639118f2017-06-19 15:48:02 -0700878 ],
879 extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -0700880
881 if len(args) != 2:
882 common.Usage(__doc__)
883 sys.exit(1)
884
885 input_zip = zipfile.ZipFile(args[0], "r")
Tao Bao2b8f4892017-06-13 12:54:58 -0700886 output_zip = zipfile.ZipFile(args[1], "w",
887 compression=zipfile.ZIP_DEFLATED,
888 allowZip64=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700889
Doug Zongker831840e2011-09-22 10:28:04 -0700890 misc_info = common.LoadInfoDict(input_zip)
891
892 BuildKeyMap(misc_info, key_mapping_options)
893
Narayan Kamatha07bf042017-08-14 14:49:21 +0100894 certmap, compressed_extension = common.ReadApkCerts(input_zip)
895 apk_key_map = GetApkCerts(certmap)
896 CheckAllApksSigned(input_zip, apk_key_map, compressed_extension)
Doug Zongkereb338ef2009-05-20 16:50:49 -0700897
898 key_passwords = common.GetKeyPasswords(set(apk_key_map.values()))
Tao Bao9aa4b9b2016-09-29 17:53:56 -0700899 platform_api_level, _ = GetApiLevelAndCodename(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800900 codename_to_api_level_map = GetCodenameToApiLevelMap(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800901
Doug Zongker412c02f2014-02-13 10:58:24 -0800902 ProcessTargetFiles(input_zip, output_zip, misc_info,
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800903 apk_key_map, key_passwords,
904 platform_api_level,
Narayan Kamatha07bf042017-08-14 14:49:21 +0100905 codename_to_api_level_map,
906 compressed_extension)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700907
Tao Bao2ed665a2015-04-01 11:21:55 -0700908 common.ZipClose(input_zip)
909 common.ZipClose(output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700910
Tianjie Xub48589a2016-08-03 19:21:52 -0700911 # Skip building userdata.img and cache.img when signing the target files.
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700912 new_args = ["--is_signing"]
913 # add_img_to_target_files builds the system image from scratch, so the
914 # recovery patch is guaranteed to be regenerated there.
915 if OPTIONS.rebuild_recovery:
916 new_args.append("--rebuild_recovery")
917 new_args.append(args[1])
Tianjie Xub48589a2016-08-03 19:21:52 -0700918 add_img_to_target_files.main(new_args)
Doug Zongker3c84f562014-07-31 11:06:30 -0700919
Tao Bao0c28d2d2017-12-24 10:37:38 -0800920 print("done.")
Doug Zongkereef39442009-04-02 12:14:19 -0700921
922
923if __name__ == '__main__':
924 try:
925 main(sys.argv[1:])
Tao Bao0c28d2d2017-12-24 10:37:38 -0800926 except common.ExternalError as e:
927 print("\n ERROR: %s\n" % (e,))
Doug Zongkereef39442009-04-02 12:14:19 -0700928 sys.exit(1)
Tao Bao639118f2017-06-19 15:48:02 -0700929 finally:
930 common.Cleanup()