| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 1 | #!/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 | """ | 
 | 18 | Signs all the APK files in a target-files zipfile, producing a new | 
 | 19 | target-files zip. | 
 | 20 |  | 
 | 21 | Usage:  sign_target_files_apks [flags] input_target_files output_target_files | 
 | 22 |  | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 23 |   -e  (--extra_apks)  <name,name,...=key> | 
| Tao Bao | aa7e993 | 2019-03-15 09:37:01 -0700 | [diff] [blame] | 24 |       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 Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 35 |  | 
| Tao Bao | 93c2a01 | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 36 |   --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 Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 42 |   -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 Zongker | 831840e | 2011-09-22 10:28:04 -0700 | [diff] [blame] | 51 |         $devkey/devkey    ==>  $dir/releasekey | 
 | 52 |         $devkey/testkey   ==>  $dir/releasekey | 
 | 53 |         $devkey/media     ==>  $dir/media | 
 | 54 |         $devkey/shared    ==>  $dir/shared | 
 | 55 |         $devkey/platform  ==>  $dir/platform | 
 | 56 |  | 
 | 57 |       where $devkey is the directory part of the value of | 
 | 58 |       default_system_dev_certificate from the input target-files's | 
 | 59 |       META/misc_info.txt.  (Defaulting to "build/target/product/security" | 
 | 60 |       if the value is not present in misc_info. | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 61 |  | 
 | 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 Zongker | 8e931bf | 2009-04-06 15:21:45 -0700 | [diff] [blame] | 64 |  | 
 | 65 |   -o  (--replace_ota_keys) | 
| Tao Bao | a80ed22 | 2016-06-16 14:41:24 -0700 | [diff] [blame] | 66 |       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 Zongker | 17aa944 | 2009-04-17 10:15:58 -0700 | [diff] [blame] | 72 |  | 
| Doug Zongker | ae87701 | 2009-04-21 10:04:51 -0700 | [diff] [blame] | 73 |   -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 Zongker | 831840e | 2011-09-22 10:28:04 -0700 | [diff] [blame] | 78 |       Default value is "-test-keys,-dev-keys,+release-keys". | 
| Doug Zongker | ae87701 | 2009-04-21 10:04:51 -0700 | [diff] [blame] | 79 |  | 
| Tao Bao | 8adcfd1 | 2016-06-17 17:01:22 -0700 | [diff] [blame] | 80 |   --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 Sridharan | 35c9b12 | 2016-06-16 19:58:44 -0700 | [diff] [blame] | 90 |   --replace_verity_keyid <path_to_X509_PEM_cert_file> | 
 | 91 |       Replace the veritykeyid in BOOT/cmdline of input_target_file_zip | 
| Tao Bao | 8adcfd1 | 2016-06-17 17:01:22 -0700 | [diff] [blame] | 92 |       with keyid of the cert pointed by <path_to_X509_PEM_cert_file>. | 
| Tao Bao | 639118f | 2017-06-19 15:48:02 -0700 | [diff] [blame] | 93 |  | 
| Tao Bao | d403e7b | 2019-05-06 12:55:42 -0700 | [diff] [blame] | 94 |   --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 Bao | 639118f | 2017-06-19 15:48:02 -0700 | [diff] [blame] | 98 |       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 Bao | d403e7b | 2019-05-06 12:55:42 -0700 | [diff] [blame] | 101 |   --avb_{apex,boot,system,system_other,vendor,dtbo,vbmeta,vbmeta_system, | 
 | 102 |          vbmeta_vendor}_extra_args <args> | 
| Tao Bao | 639118f | 2017-06-19 15:48:02 -0700 | [diff] [blame] | 103 |       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 Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 106 | """ | 
 | 107 |  | 
| Tao Bao | 0c28d2d | 2017-12-24 10:37:38 -0800 | [diff] [blame] | 108 | from __future__ import print_function | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 109 |  | 
| Robert Craig | 817c574 | 2013-04-19 10:59:22 -0400 | [diff] [blame] | 110 | import base64 | 
| Doug Zongker | 8e931bf | 2009-04-06 15:21:45 -0700 | [diff] [blame] | 111 | import copy | 
| Robert Craig | 817c574 | 2013-04-19 10:59:22 -0400 | [diff] [blame] | 112 | import errno | 
| Narayan Kamath | a07bf04 | 2017-08-14 14:49:21 +0100 | [diff] [blame] | 113 | import gzip | 
| Tao Bao | aa7e993 | 2019-03-15 09:37:01 -0700 | [diff] [blame] | 114 | import itertools | 
| Tao Bao | badceb2 | 2019-03-15 09:33:43 -0700 | [diff] [blame] | 115 | import logging | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 116 | import os | 
 | 117 | import re | 
| Narayan Kamath | a07bf04 | 2017-08-14 14:49:21 +0100 | [diff] [blame] | 118 | import shutil | 
| Tao Bao | 9fdd00f | 2017-07-12 11:57:05 -0700 | [diff] [blame] | 119 | import stat | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 120 | import subprocess | 
| Tao Bao | 0c28d2d | 2017-12-24 10:37:38 -0800 | [diff] [blame] | 121 | import sys | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 122 | import tempfile | 
 | 123 | import zipfile | 
| Tao Bao | 6647263 | 2017-12-04 17:16:36 -0800 | [diff] [blame] | 124 | from xml.etree import ElementTree | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 125 |  | 
| Doug Zongker | 3c84f56 | 2014-07-31 11:06:30 -0700 | [diff] [blame] | 126 | import add_img_to_target_files | 
| Tao Bao | aa7e993 | 2019-03-15 09:37:01 -0700 | [diff] [blame] | 127 | import apex_utils | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 128 | import common | 
 | 129 |  | 
| Tao Bao | 0c28d2d | 2017-12-24 10:37:38 -0800 | [diff] [blame] | 130 |  | 
 | 131 | if sys.hexversion < 0x02070000: | 
 | 132 |   print("Python 2.7 or newer is required.", file=sys.stderr) | 
 | 133 |   sys.exit(1) | 
 | 134 |  | 
 | 135 |  | 
| Tao Bao | badceb2 | 2019-03-15 09:33:43 -0700 | [diff] [blame] | 136 | logger = logging.getLogger(__name__) | 
 | 137 |  | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 138 | OPTIONS = common.OPTIONS | 
 | 139 |  | 
 | 140 | OPTIONS.extra_apks = {} | 
| Tao Bao | aa7e993 | 2019-03-15 09:37:01 -0700 | [diff] [blame] | 141 | OPTIONS.extra_apex_payload_keys = {} | 
| Tao Bao | 93c2a01 | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 142 | OPTIONS.skip_apks_with_path_prefix = set() | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 143 | OPTIONS.key_map = {} | 
| Tianjie Xu | 616fbeb | 2017-05-23 14:51:02 -0700 | [diff] [blame] | 144 | OPTIONS.rebuild_recovery = False | 
| Doug Zongker | 8e931bf | 2009-04-06 15:21:45 -0700 | [diff] [blame] | 145 | OPTIONS.replace_ota_keys = False | 
| Geremy Condra | f19b365 | 2014-07-29 17:54:54 -0700 | [diff] [blame] | 146 | OPTIONS.replace_verity_public_key = False | 
 | 147 | OPTIONS.replace_verity_private_key = False | 
| Badhri Jagan Sridharan | 35c9b12 | 2016-06-16 19:58:44 -0700 | [diff] [blame] | 148 | OPTIONS.replace_verity_keyid = False | 
| Doug Zongker | 831840e | 2011-09-22 10:28:04 -0700 | [diff] [blame] | 149 | OPTIONS.tag_changes = ("-test-keys", "-dev-keys", "+release-keys") | 
| Tao Bao | 639118f | 2017-06-19 15:48:02 -0700 | [diff] [blame] | 150 | OPTIONS.avb_keys = {} | 
 | 151 | OPTIONS.avb_algorithms = {} | 
 | 152 | OPTIONS.avb_extra_args = {} | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 153 |  | 
| Tao Bao | 0c28d2d | 2017-12-24 10:37:38 -0800 | [diff] [blame] | 154 |  | 
| Narayan Kamath | a07bf04 | 2017-08-14 14:49:21 +0100 | [diff] [blame] | 155 | def GetApkCerts(certmap): | 
| Doug Zongker | f6a53aa | 2009-12-15 15:06:55 -0800 | [diff] [blame] | 156 |   # apply the key remapping to the contents of the file | 
 | 157 |   for apk, cert in certmap.iteritems(): | 
 | 158 |     certmap[apk] = OPTIONS.key_map.get(cert, cert) | 
 | 159 |  | 
 | 160 |   # apply all the -e options, overriding anything in the file | 
| Doug Zongker | ad88c7c | 2009-04-14 12:34:27 -0700 | [diff] [blame] | 161 |   for apk, cert in OPTIONS.extra_apks.iteritems(): | 
| Doug Zongker | decf995 | 2009-12-15 17:27:49 -0800 | [diff] [blame] | 162 |     if not cert: | 
 | 163 |       cert = "PRESIGNED" | 
| Doug Zongker | ad88c7c | 2009-04-14 12:34:27 -0700 | [diff] [blame] | 164 |     certmap[apk] = OPTIONS.key_map.get(cert, cert) | 
| Doug Zongker | f6a53aa | 2009-12-15 15:06:55 -0800 | [diff] [blame] | 165 |  | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 166 |   return certmap | 
 | 167 |  | 
 | 168 |  | 
| Tao Bao | aa7e993 | 2019-03-15 09:37:01 -0700 | [diff] [blame] | 169 | def GetApexKeys(keys_info, key_map): | 
 | 170 |   """Gets APEX payload and container signing keys by applying the mapping rules. | 
 | 171 |  | 
| Tao Bao | e134399 | 2019-03-19 12:24:03 -0700 | [diff] [blame] | 172 |   Presigned payload / container keys will be set accordingly. | 
| Tao Bao | aa7e993 | 2019-03-15 09:37:01 -0700 | [diff] [blame] | 173 |  | 
 | 174 |   Args: | 
 | 175 |     keys_info: A dict that maps from APEX filenames to a tuple of (payload_key, | 
 | 176 |         container_key). | 
 | 177 |     key_map: A dict that overrides the keys, specified via command-line input. | 
 | 178 |  | 
 | 179 |   Returns: | 
 | 180 |     A dict that contains the updated APEX key mapping, which should be used for | 
 | 181 |     the current signing. | 
 | 182 |   """ | 
 | 183 |   # Apply all the --extra_apex_payload_key options to override the payload | 
 | 184 |   # signing keys in the given keys_info. | 
 | 185 |   for apex, key in OPTIONS.extra_apex_payload_keys.items(): | 
| Tao Bao | e134399 | 2019-03-19 12:24:03 -0700 | [diff] [blame] | 186 |     if not key: | 
 | 187 |       key = 'PRESIGNED' | 
| Tao Bao | b369c72 | 2019-07-11 11:52:52 -0700 | [diff] [blame] | 188 |     if apex not in keys_info: | 
 | 189 |       logger.warning('Failed to find %s in target_files; Ignored', apex) | 
 | 190 |       continue | 
| Tao Bao | aa7e993 | 2019-03-15 09:37:01 -0700 | [diff] [blame] | 191 |     keys_info[apex] = (key, keys_info[apex][1]) | 
 | 192 |  | 
 | 193 |   # Apply the key remapping to container keys. | 
 | 194 |   for apex, (payload_key, container_key) in keys_info.items(): | 
 | 195 |     keys_info[apex] = (payload_key, key_map.get(container_key, container_key)) | 
 | 196 |  | 
 | 197 |   # Apply all the --extra_apks options to override the container keys. | 
 | 198 |   for apex, key in OPTIONS.extra_apks.items(): | 
 | 199 |     # Skip non-APEX containers. | 
 | 200 |     if apex not in keys_info: | 
 | 201 |       continue | 
| Tao Bao | e134399 | 2019-03-19 12:24:03 -0700 | [diff] [blame] | 202 |     if not key: | 
 | 203 |       key = 'PRESIGNED' | 
| Tao Bao | fa9de0a | 2019-03-18 10:24:17 -0700 | [diff] [blame] | 204 |     keys_info[apex] = (keys_info[apex][0], key_map.get(key, key)) | 
| Tao Bao | aa7e993 | 2019-03-15 09:37:01 -0700 | [diff] [blame] | 205 |  | 
 | 206 |   return keys_info | 
 | 207 |  | 
 | 208 |  | 
| Tao Bao | 93c2a01 | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 209 | def GetApkFileInfo(filename, compressed_extension, skipped_prefixes): | 
| Tao Bao | 11f955c | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 210 |   """Returns the APK info based on the given filename. | 
 | 211 |  | 
 | 212 |   Checks if the given filename (with path) looks like an APK file, by taking the | 
| Tao Bao | 93c2a01 | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 213 |   compressed extension into consideration. If it appears to be an APK file, | 
 | 214 |   further checks if the APK file should be skipped when signing, based on the | 
 | 215 |   given path prefixes. | 
| Tao Bao | 11f955c | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 216 |  | 
 | 217 |   Args: | 
 | 218 |     filename: Path to the file. | 
 | 219 |     compressed_extension: The extension string of compressed APKs (e.g. ".gz"), | 
 | 220 |         or None if there's no compressed APKs. | 
| Tao Bao | 93c2a01 | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 221 |     skipped_prefixes: A set/list/tuple of the path prefixes to be skipped. | 
| Tao Bao | 11f955c | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 222 |  | 
 | 223 |   Returns: | 
| Tao Bao | 93c2a01 | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 224 |     (is_apk, is_compressed, should_be_skipped): is_apk indicates whether the | 
 | 225 |     given filename is an APK file. is_compressed indicates whether the APK file | 
 | 226 |     is compressed (only meaningful when is_apk is True). should_be_skipped | 
 | 227 |     indicates whether the filename matches any of the given prefixes to be | 
 | 228 |     skipped. | 
| Tao Bao | 11f955c | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 229 |  | 
 | 230 |   Raises: | 
| Tao Bao | 93c2a01 | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 231 |     AssertionError: On invalid compressed_extension or skipped_prefixes inputs. | 
| Tao Bao | 11f955c | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 232 |   """ | 
 | 233 |   assert compressed_extension is None or compressed_extension.startswith('.'), \ | 
 | 234 |       "Invalid compressed_extension arg: '{}'".format(compressed_extension) | 
 | 235 |  | 
| Tao Bao | 93c2a01 | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 236 |   # skipped_prefixes should be one of set/list/tuple types. Other types such as | 
 | 237 |   # str shouldn't be accepted. | 
| Tao Bao | badceb2 | 2019-03-15 09:33:43 -0700 | [diff] [blame] | 238 |   assert isinstance(skipped_prefixes, (set, list, tuple)), \ | 
 | 239 |       "Invalid skipped_prefixes input type: {}".format(type(skipped_prefixes)) | 
| Tao Bao | 93c2a01 | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 240 |  | 
| Tao Bao | 11f955c | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 241 |   compressed_apk_extension = ( | 
 | 242 |       ".apk" + compressed_extension if compressed_extension else None) | 
 | 243 |   is_apk = (filename.endswith(".apk") or | 
 | 244 |             (compressed_apk_extension and | 
 | 245 |              filename.endswith(compressed_apk_extension))) | 
 | 246 |   if not is_apk: | 
| Tao Bao | 93c2a01 | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 247 |     return (False, False, False) | 
| Tao Bao | 11f955c | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 248 |  | 
 | 249 |   is_compressed = (compressed_apk_extension and | 
 | 250 |                    filename.endswith(compressed_apk_extension)) | 
| Tao Bao | 93c2a01 | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 251 |   should_be_skipped = filename.startswith(tuple(skipped_prefixes)) | 
 | 252 |   return (True, is_compressed, should_be_skipped) | 
| Tao Bao | 11f955c | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 253 |  | 
 | 254 |  | 
| Tao Bao | aa7e993 | 2019-03-15 09:37:01 -0700 | [diff] [blame] | 255 | def CheckApkAndApexKeysAvailable(input_tf_zip, known_keys, | 
| Tao Bao | e134399 | 2019-03-19 12:24:03 -0700 | [diff] [blame] | 256 |                                  compressed_extension, apex_keys): | 
| Tao Bao | aa7e993 | 2019-03-15 09:37:01 -0700 | [diff] [blame] | 257 |   """Checks that all the APKs and APEXes have keys specified. | 
| Tao Bao | 11f955c | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 258 |  | 
 | 259 |   Args: | 
 | 260 |     input_tf_zip: An open target_files zip file. | 
| Tao Bao | aa7e993 | 2019-03-15 09:37:01 -0700 | [diff] [blame] | 261 |     known_keys: A set of APKs and APEXes that have known signing keys. | 
| Tao Bao | 11f955c | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 262 |     compressed_extension: The extension string of compressed APKs, such as | 
| Tao Bao | aa7e993 | 2019-03-15 09:37:01 -0700 | [diff] [blame] | 263 |         '.gz', or None if there's no compressed APKs. | 
| Tao Bao | e134399 | 2019-03-19 12:24:03 -0700 | [diff] [blame] | 264 |     apex_keys: A dict that contains the key mapping from APEX name to | 
 | 265 |         (payload_key, container_key). | 
| Tao Bao | 11f955c | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 266 |  | 
 | 267 |   Raises: | 
| Tao Bao | aa7e993 | 2019-03-15 09:37:01 -0700 | [diff] [blame] | 268 |     AssertionError: On finding unknown APKs and APEXes. | 
| Tao Bao | 11f955c | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 269 |   """ | 
| Tao Bao | aa7e993 | 2019-03-15 09:37:01 -0700 | [diff] [blame] | 270 |   unknown_files = [] | 
| Doug Zongker | eb338ef | 2009-05-20 16:50:49 -0700 | [diff] [blame] | 271 |   for info in input_tf_zip.infolist(): | 
| Tao Bao | aa7e993 | 2019-03-15 09:37:01 -0700 | [diff] [blame] | 272 |     # Handle APEXes first, e.g. SYSTEM/apex/com.android.tzdata.apex. | 
 | 273 |     if (info.filename.startswith('SYSTEM/apex') and | 
 | 274 |         info.filename.endswith('.apex')): | 
 | 275 |       name = os.path.basename(info.filename) | 
 | 276 |       if name not in known_keys: | 
 | 277 |         unknown_files.append(name) | 
 | 278 |       continue | 
 | 279 |  | 
 | 280 |     # And APKs. | 
| Tao Bao | 93c2a01 | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 281 |     (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo( | 
 | 282 |         info.filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix) | 
 | 283 |     if not is_apk or should_be_skipped: | 
| Tao Bao | 11f955c | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 284 |       continue | 
| Tao Bao | aa7e993 | 2019-03-15 09:37:01 -0700 | [diff] [blame] | 285 |  | 
| Tao Bao | 11f955c | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 286 |     name = os.path.basename(info.filename) | 
 | 287 |     if is_compressed: | 
 | 288 |       name = name[:-len(compressed_extension)] | 
| Tao Bao | aa7e993 | 2019-03-15 09:37:01 -0700 | [diff] [blame] | 289 |     if name not in known_keys: | 
 | 290 |       unknown_files.append(name) | 
| Tao Bao | 11f955c | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 291 |  | 
| Tao Bao | aa7e993 | 2019-03-15 09:37:01 -0700 | [diff] [blame] | 292 |   assert not unknown_files, \ | 
| Tao Bao | 11f955c | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 293 |       ("No key specified for:\n  {}\n" | 
 | 294 |        "Use '-e <apkname>=' to specify a key (which may be an empty string to " | 
| Tao Bao | aa7e993 | 2019-03-15 09:37:01 -0700 | [diff] [blame] | 295 |        "not sign this apk).".format("\n  ".join(unknown_files))) | 
| Doug Zongker | eb338ef | 2009-05-20 16:50:49 -0700 | [diff] [blame] | 296 |  | 
| Tao Bao | e134399 | 2019-03-19 12:24:03 -0700 | [diff] [blame] | 297 |   # For all the APEXes, double check that we won't have an APEX that has only | 
 | 298 |   # one of the payload / container keys set. | 
 | 299 |   if not apex_keys: | 
 | 300 |     return | 
 | 301 |  | 
 | 302 |   invalid_apexes = [] | 
 | 303 |   for info in input_tf_zip.infolist(): | 
 | 304 |     if (not info.filename.startswith('SYSTEM/apex') or | 
 | 305 |         not info.filename.endswith('.apex')): | 
 | 306 |       continue | 
 | 307 |  | 
 | 308 |     name = os.path.basename(info.filename) | 
 | 309 |     (payload_key, container_key) = apex_keys[name] | 
 | 310 |     if ((payload_key in common.SPECIAL_CERT_STRINGS and | 
 | 311 |          container_key not in common.SPECIAL_CERT_STRINGS) or | 
 | 312 |         (payload_key not in common.SPECIAL_CERT_STRINGS and | 
 | 313 |          container_key in common.SPECIAL_CERT_STRINGS)): | 
 | 314 |       invalid_apexes.append( | 
 | 315 |           "{}: payload_key {}, container_key {}".format( | 
 | 316 |               name, payload_key, container_key)) | 
 | 317 |  | 
 | 318 |   assert not invalid_apexes, \ | 
 | 319 |       "Invalid APEX keys specified:\n  {}\n".format( | 
 | 320 |           "\n  ".join(invalid_apexes)) | 
 | 321 |  | 
| Doug Zongker | eb338ef | 2009-05-20 16:50:49 -0700 | [diff] [blame] | 322 |  | 
| Narayan Kamath | a07bf04 | 2017-08-14 14:49:21 +0100 | [diff] [blame] | 323 | def SignApk(data, keyname, pw, platform_api_level, codename_to_api_level_map, | 
 | 324 |             is_compressed): | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 325 |   unsigned = tempfile.NamedTemporaryFile() | 
 | 326 |   unsigned.write(data) | 
 | 327 |   unsigned.flush() | 
 | 328 |  | 
| Narayan Kamath | a07bf04 | 2017-08-14 14:49:21 +0100 | [diff] [blame] | 329 |   if is_compressed: | 
 | 330 |     uncompressed = tempfile.NamedTemporaryFile() | 
| Tao Bao | 0c28d2d | 2017-12-24 10:37:38 -0800 | [diff] [blame] | 331 |     with gzip.open(unsigned.name, "rb") as in_file, \ | 
 | 332 |          open(uncompressed.name, "wb") as out_file: | 
| Narayan Kamath | a07bf04 | 2017-08-14 14:49:21 +0100 | [diff] [blame] | 333 |       shutil.copyfileobj(in_file, out_file) | 
 | 334 |  | 
 | 335 |     # Finally, close the "unsigned" file (which is gzip compressed), and then | 
 | 336 |     # replace it with the uncompressed version. | 
 | 337 |     # | 
 | 338 |     # TODO(narayan): All this nastiness can be avoided if python 3.2 is in use, | 
 | 339 |     # we could just gzip / gunzip in-memory buffers instead. | 
 | 340 |     unsigned.close() | 
 | 341 |     unsigned = uncompressed | 
 | 342 |  | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 343 |   signed = tempfile.NamedTemporaryFile() | 
 | 344 |  | 
| Alex Klyubin | 2cfd1d1 | 2016-01-13 10:32:47 -0800 | [diff] [blame] | 345 |   # For pre-N builds, don't upgrade to SHA-256 JAR signatures based on the APK's | 
 | 346 |   # minSdkVersion to avoid increasing incremental OTA update sizes. If an APK | 
 | 347 |   # didn't change, we don't want its signature to change due to the switch | 
 | 348 |   # from SHA-1 to SHA-256. | 
 | 349 |   # By default, APK signer chooses SHA-256 signatures if the APK's minSdkVersion | 
 | 350 |   # is 18 or higher. For pre-N builds we disable this mechanism by pretending | 
 | 351 |   # that the APK's minSdkVersion is 1. | 
 | 352 |   # For N+ builds, we let APK signer rely on the APK's minSdkVersion to | 
 | 353 |   # determine whether to use SHA-256. | 
 | 354 |   min_api_level = None | 
 | 355 |   if platform_api_level > 23: | 
 | 356 |     # Let APK signer choose whether to use SHA-1 or SHA-256, based on the APK's | 
 | 357 |     # minSdkVersion attribute | 
 | 358 |     min_api_level = None | 
 | 359 |   else: | 
 | 360 |     # Force APK signer to use SHA-1 | 
 | 361 |     min_api_level = 1 | 
 | 362 |  | 
 | 363 |   common.SignFile(unsigned.name, signed.name, keyname, pw, | 
| Tao Bao | 0c28d2d | 2017-12-24 10:37:38 -0800 | [diff] [blame] | 364 |                   min_api_level=min_api_level, | 
 | 365 |                   codename_to_api_level_map=codename_to_api_level_map) | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 366 |  | 
| Tao Bao | 0c28d2d | 2017-12-24 10:37:38 -0800 | [diff] [blame] | 367 |   data = None | 
| Narayan Kamath | a07bf04 | 2017-08-14 14:49:21 +0100 | [diff] [blame] | 368 |   if is_compressed: | 
 | 369 |     # Recompress the file after it has been signed. | 
 | 370 |     compressed = tempfile.NamedTemporaryFile() | 
| Tao Bao | 0c28d2d | 2017-12-24 10:37:38 -0800 | [diff] [blame] | 371 |     with open(signed.name, "rb") as in_file, \ | 
 | 372 |          gzip.open(compressed.name, "wb") as out_file: | 
| Narayan Kamath | a07bf04 | 2017-08-14 14:49:21 +0100 | [diff] [blame] | 373 |       shutil.copyfileobj(in_file, out_file) | 
 | 374 |  | 
 | 375 |     data = compressed.read() | 
 | 376 |     compressed.close() | 
 | 377 |   else: | 
 | 378 |     data = signed.read() | 
 | 379 |  | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 380 |   unsigned.close() | 
 | 381 |   signed.close() | 
 | 382 |  | 
 | 383 |   return data | 
 | 384 |  | 
 | 385 |  | 
| Doug Zongker | 412c02f | 2014-02-13 10:58:24 -0800 | [diff] [blame] | 386 | def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info, | 
| Tao Bao | aa7e993 | 2019-03-15 09:37:01 -0700 | [diff] [blame] | 387 |                        apk_keys, apex_keys, key_passwords, | 
 | 388 |                        platform_api_level, codename_to_api_level_map, | 
| Narayan Kamath | a07bf04 | 2017-08-14 14:49:21 +0100 | [diff] [blame] | 389 |                        compressed_extension): | 
| Tao Bao | 93c2a01 | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 390 |   # maxsize measures the maximum filename length, including the ones to be | 
 | 391 |   # skipped. | 
| Tao Bao | 0c28d2d | 2017-12-24 10:37:38 -0800 | [diff] [blame] | 392 |   maxsize = max( | 
 | 393 |       [len(os.path.basename(i.filename)) for i in input_tf_zip.infolist() | 
| Tao Bao | 93c2a01 | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 394 |        if GetApkFileInfo(i.filename, compressed_extension, [])[0]]) | 
| Tao Bao | a80ed22 | 2016-06-16 14:41:24 -0700 | [diff] [blame] | 395 |   system_root_image = misc_info.get("system_root_image") == "true" | 
| Doug Zongker | 412c02f | 2014-02-13 10:58:24 -0800 | [diff] [blame] | 396 |  | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 397 |   for info in input_tf_zip.infolist(): | 
| Tao Bao | 11f955c | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 398 |     filename = info.filename | 
 | 399 |     if filename.startswith("IMAGES/"): | 
| Dan Albert | 8b72aef | 2015-03-23 19:13:21 -0700 | [diff] [blame] | 400 |       continue | 
| Doug Zongker | 3c84f56 | 2014-07-31 11:06:30 -0700 | [diff] [blame] | 401 |  | 
| Tao Bao | 33bf268 | 2019-01-11 12:37:35 -0800 | [diff] [blame] | 402 |     # Skip split super images, which will be re-generated during signing. | 
 | 403 |     if filename.startswith("OTA/") and filename.endswith(".img"): | 
 | 404 |       continue | 
 | 405 |  | 
| Tao Bao | 11f955c | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 406 |     data = input_tf_zip.read(filename) | 
| Doug Zongker | 8e931bf | 2009-04-06 15:21:45 -0700 | [diff] [blame] | 407 |     out_info = copy.copy(info) | 
| Tao Bao | 93c2a01 | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 408 |     (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo( | 
 | 409 |         filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix) | 
 | 410 |  | 
 | 411 |     if is_apk and should_be_skipped: | 
 | 412 |       # Copy skipped APKs verbatim. | 
 | 413 |       print( | 
 | 414 |           "NOT signing: %s\n" | 
 | 415 |           "        (skipped due to matching prefix)" % (filename,)) | 
 | 416 |       common.ZipWriteStr(output_tf_zip, out_info, data) | 
| Doug Zongker | 412c02f | 2014-02-13 10:58:24 -0800 | [diff] [blame] | 417 |  | 
| Tao Bao | f2cffbd | 2015-07-22 12:33:18 -0700 | [diff] [blame] | 418 |     # Sign APKs. | 
| Tao Bao | 93c2a01 | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 419 |     elif is_apk: | 
| Tao Bao | 11f955c | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 420 |       name = os.path.basename(filename) | 
| Narayan Kamath | a07bf04 | 2017-08-14 14:49:21 +0100 | [diff] [blame] | 421 |       if is_compressed: | 
 | 422 |         name = name[:-len(compressed_extension)] | 
 | 423 |  | 
| Tao Bao | aa7e993 | 2019-03-15 09:37:01 -0700 | [diff] [blame] | 424 |       key = apk_keys[name] | 
| Doug Zongker | f6a53aa | 2009-12-15 15:06:55 -0800 | [diff] [blame] | 425 |       if key not in common.SPECIAL_CERT_STRINGS: | 
| Tao Bao | 0c28d2d | 2017-12-24 10:37:38 -0800 | [diff] [blame] | 426 |         print("    signing: %-*s (%s)" % (maxsize, name, key)) | 
| Alex Klyubin | 2cfd1d1 | 2016-01-13 10:32:47 -0800 | [diff] [blame] | 427 |         signed_data = SignApk(data, key, key_passwords[key], platform_api_level, | 
| Tao Bao | 0c28d2d | 2017-12-24 10:37:38 -0800 | [diff] [blame] | 428 |                               codename_to_api_level_map, is_compressed) | 
| Tao Bao | 2ed665a | 2015-04-01 11:21:55 -0700 | [diff] [blame] | 429 |         common.ZipWriteStr(output_tf_zip, out_info, signed_data) | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 430 |       else: | 
 | 431 |         # an APK we're not supposed to sign. | 
| Tao Bao | 93c2a01 | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 432 |         print( | 
 | 433 |             "NOT signing: %s\n" | 
 | 434 |             "        (skipped due to special cert string)" % (name,)) | 
| Tao Bao | 2ed665a | 2015-04-01 11:21:55 -0700 | [diff] [blame] | 435 |         common.ZipWriteStr(output_tf_zip, out_info, data) | 
| Tao Bao | a80ed22 | 2016-06-16 14:41:24 -0700 | [diff] [blame] | 436 |  | 
| Tao Bao | aa7e993 | 2019-03-15 09:37:01 -0700 | [diff] [blame] | 437 |     # Sign bundled APEX files. | 
 | 438 |     elif filename.startswith("SYSTEM/apex") and filename.endswith(".apex"): | 
 | 439 |       name = os.path.basename(filename) | 
 | 440 |       payload_key, container_key = apex_keys[name] | 
 | 441 |  | 
| Tao Bao | e134399 | 2019-03-19 12:24:03 -0700 | [diff] [blame] | 442 |       # We've asserted not having a case with only one of them PRESIGNED. | 
 | 443 |       if (payload_key not in common.SPECIAL_CERT_STRINGS and | 
 | 444 |           container_key not in common.SPECIAL_CERT_STRINGS): | 
 | 445 |         print("    signing: %-*s container (%s)" % ( | 
 | 446 |             maxsize, name, container_key)) | 
 | 447 |         print("           : %-*s payload   (%s)" % ( | 
 | 448 |             maxsize, name, payload_key)) | 
| Tao Bao | aa7e993 | 2019-03-15 09:37:01 -0700 | [diff] [blame] | 449 |  | 
| Tao Bao | f52dbb8 | 2019-05-09 16:54:15 -0700 | [diff] [blame] | 450 |         signed_apex = apex_utils.SignApex( | 
| Tao Bao | e134399 | 2019-03-19 12:24:03 -0700 | [diff] [blame] | 451 |             data, | 
 | 452 |             payload_key, | 
 | 453 |             container_key, | 
 | 454 |             key_passwords[container_key], | 
 | 455 |             codename_to_api_level_map, | 
 | 456 |             OPTIONS.avb_extra_args.get('apex')) | 
 | 457 |         common.ZipWrite(output_tf_zip, signed_apex, filename) | 
| Tao Bao | aa7e993 | 2019-03-15 09:37:01 -0700 | [diff] [blame] | 458 |  | 
| Tao Bao | e134399 | 2019-03-19 12:24:03 -0700 | [diff] [blame] | 459 |       else: | 
 | 460 |         print( | 
 | 461 |             "NOT signing: %s\n" | 
 | 462 |             "        (skipped due to special cert string)" % (name,)) | 
 | 463 |         common.ZipWriteStr(output_tf_zip, out_info, data) | 
| Tao Bao | aa7e993 | 2019-03-15 09:37:01 -0700 | [diff] [blame] | 464 |  | 
 | 465 |     # AVB public keys for the installed APEXes, which will be updated later. | 
 | 466 |     elif (os.path.dirname(filename) == 'SYSTEM/etc/security/apex' and | 
 | 467 |           filename != 'SYSTEM/etc/security/apex/'): | 
 | 468 |       continue | 
 | 469 |  | 
| Tao Bao | a80ed22 | 2016-06-16 14:41:24 -0700 | [diff] [blame] | 470 |     # System properties. | 
| Tao Bao | 11f955c | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 471 |     elif filename in ("SYSTEM/build.prop", | 
 | 472 |                       "VENDOR/build.prop", | 
| Magnus Strandh | 6396797 | 2019-05-01 23:09:30 +0200 | [diff] [blame] | 473 |                       "SYSTEM/vendor/build.prop", | 
| Bowgo Tsai | 33ff602 | 2019-05-17 23:21:48 +0800 | [diff] [blame] | 474 |                       "ODM/build.prop",  # legacy | 
 | 475 |                       "ODM/etc/build.prop", | 
 | 476 |                       "VENDOR/odm/build.prop",  # legacy | 
 | 477 |                       "VENDOR/odm/etc/build.prop", | 
| Magnus Strandh | 6396797 | 2019-05-01 23:09:30 +0200 | [diff] [blame] | 478 |                       "PRODUCT/build.prop", | 
 | 479 |                       "SYSTEM/product/build.prop", | 
 | 480 |                       "PRODUCT_SERVICES/build.prop", | 
 | 481 |                       "SYSTEM/product_services/build.prop", | 
| Tao Bao | 11f955c | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 482 |                       "SYSTEM/etc/prop.default", | 
 | 483 |                       "BOOT/RAMDISK/prop.default", | 
 | 484 |                       "BOOT/RAMDISK/default.prop",  # legacy | 
 | 485 |                       "ROOT/default.prop",  # legacy | 
 | 486 |                       "RECOVERY/RAMDISK/prop.default", | 
 | 487 |                       "RECOVERY/RAMDISK/default.prop"):  # legacy | 
 | 488 |       print("Rewriting %s:" % (filename,)) | 
| Hung-ying Tyan | 7eb6a92 | 2017-05-01 21:56:26 +0800 | [diff] [blame] | 489 |       if stat.S_ISLNK(info.external_attr >> 16): | 
 | 490 |         new_data = data | 
 | 491 |       else: | 
| Tao Bao | a7054ee | 2017-12-08 14:42:16 -0800 | [diff] [blame] | 492 |         new_data = RewriteProps(data) | 
| Tao Bao | 2ed665a | 2015-04-01 11:21:55 -0700 | [diff] [blame] | 493 |       common.ZipWriteStr(output_tf_zip, out_info, new_data) | 
| Tao Bao | a80ed22 | 2016-06-16 14:41:24 -0700 | [diff] [blame] | 494 |  | 
| Tao Bao | 6647263 | 2017-12-04 17:16:36 -0800 | [diff] [blame] | 495 |     # Replace the certs in *mac_permissions.xml (there could be multiple, such | 
 | 496 |     # as {system,vendor}/etc/selinux/{plat,nonplat}_mac_permissions.xml). | 
| Tao Bao | 11f955c | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 497 |     elif filename.endswith("mac_permissions.xml"): | 
 | 498 |       print("Rewriting %s with new keys." % (filename,)) | 
| Robert Craig | 817c574 | 2013-04-19 10:59:22 -0400 | [diff] [blame] | 499 |       new_data = ReplaceCerts(data) | 
| Tao Bao | 2ed665a | 2015-04-01 11:21:55 -0700 | [diff] [blame] | 500 |       common.ZipWriteStr(output_tf_zip, out_info, new_data) | 
| Tao Bao | a80ed22 | 2016-06-16 14:41:24 -0700 | [diff] [blame] | 501 |  | 
| Tianjie Xu | 616fbeb | 2017-05-23 14:51:02 -0700 | [diff] [blame] | 502 |     # Ask add_img_to_target_files to rebuild the recovery patch if needed. | 
| Tao Bao | 11f955c | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 503 |     elif filename in ("SYSTEM/recovery-from-boot.p", | 
 | 504 |                       "SYSTEM/etc/recovery.img", | 
 | 505 |                       "SYSTEM/bin/install-recovery.sh"): | 
| Tianjie Xu | 616fbeb | 2017-05-23 14:51:02 -0700 | [diff] [blame] | 506 |       OPTIONS.rebuild_recovery = True | 
| Tao Bao | a80ed22 | 2016-06-16 14:41:24 -0700 | [diff] [blame] | 507 |  | 
| Tianjie Xu | ffbe6b9 | 2018-10-19 14:34:15 -0700 | [diff] [blame] | 508 |     # Don't copy OTA certs if we're replacing them. | 
| Tao Bao | 696bb33 | 2018-08-17 16:27:01 -0700 | [diff] [blame] | 509 |     elif ( | 
 | 510 |         OPTIONS.replace_ota_keys and | 
 | 511 |         filename in ( | 
| Tianjie Xu | ffbe6b9 | 2018-10-19 14:34:15 -0700 | [diff] [blame] | 512 |             "BOOT/RAMDISK/system/etc/security/otacerts.zip", | 
| Tao Bao | 696bb33 | 2018-08-17 16:27:01 -0700 | [diff] [blame] | 513 |             "BOOT/RAMDISK/system/etc/update_engine/update-payload-key.pub.pem", | 
| Tianjie Xu | ffbe6b9 | 2018-10-19 14:34:15 -0700 | [diff] [blame] | 514 |             "RECOVERY/RAMDISK/system/etc/security/otacerts.zip", | 
| Tao Bao | 696bb33 | 2018-08-17 16:27:01 -0700 | [diff] [blame] | 515 |             "SYSTEM/etc/security/otacerts.zip", | 
 | 516 |             "SYSTEM/etc/update_engine/update-payload-key.pub.pem")): | 
| Doug Zongker | 412c02f | 2014-02-13 10:58:24 -0800 | [diff] [blame] | 517 |       pass | 
| Tao Bao | a80ed22 | 2016-06-16 14:41:24 -0700 | [diff] [blame] | 518 |  | 
| Tao Bao | 46a5999 | 2017-06-05 11:55:16 -0700 | [diff] [blame] | 519 |     # Skip META/misc_info.txt since we will write back the new values later. | 
| Tao Bao | 11f955c | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 520 |     elif filename == "META/misc_info.txt": | 
| Geremy Condra | f19b365 | 2014-07-29 17:54:54 -0700 | [diff] [blame] | 521 |       pass | 
| Tao Bao | 8adcfd1 | 2016-06-17 17:01:22 -0700 | [diff] [blame] | 522 |  | 
 | 523 |     # Skip verity public key if we will replace it. | 
| Michael Runge | 947894f | 2014-10-14 20:58:38 -0700 | [diff] [blame] | 524 |     elif (OPTIONS.replace_verity_public_key and | 
| Tao Bao | 11f955c | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 525 |           filename in ("BOOT/RAMDISK/verity_key", | 
 | 526 |                        "ROOT/verity_key")): | 
| Geremy Condra | f19b365 | 2014-07-29 17:54:54 -0700 | [diff] [blame] | 527 |       pass | 
| Tao Bao | a80ed22 | 2016-06-16 14:41:24 -0700 | [diff] [blame] | 528 |  | 
| Tao Bao | 8adcfd1 | 2016-06-17 17:01:22 -0700 | [diff] [blame] | 529 |     # Skip verity keyid (for system_root_image use) if we will replace it. | 
| Tao Bao | 11f955c | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 530 |     elif OPTIONS.replace_verity_keyid and filename == "BOOT/cmdline": | 
| Badhri Jagan Sridharan | 35c9b12 | 2016-06-16 19:58:44 -0700 | [diff] [blame] | 531 |       pass | 
 | 532 |  | 
| Tianjie Xu | 4f09900 | 2016-08-11 18:04:27 -0700 | [diff] [blame] | 533 |     # Skip the care_map as we will regenerate the system/vendor images. | 
| Tianjie Xu | 4c05f4a | 2018-09-14 16:24:41 -0700 | [diff] [blame] | 534 |     elif filename == "META/care_map.pb" or filename == "META/care_map.txt": | 
| Tianjie Xu | 4f09900 | 2016-08-11 18:04:27 -0700 | [diff] [blame] | 535 |       pass | 
 | 536 |  | 
| Bowgo Tsai | e4544b1 | 2019-02-27 10:15:51 +0800 | [diff] [blame] | 537 |     # Updates system_other.avbpubkey in /product/etc/. | 
 | 538 |     elif filename in ( | 
 | 539 |         "PRODUCT/etc/security/avb/system_other.avbpubkey", | 
 | 540 |         "SYSTEM/product/etc/security/avb/system_other.avbpubkey"): | 
 | 541 |       # Only update system_other's public key, if the corresponding signing | 
 | 542 |       # key is specified via --avb_system_other_key. | 
 | 543 |       signing_key = OPTIONS.avb_keys.get("system_other") | 
 | 544 |       if signing_key: | 
 | 545 |         public_key = common.ExtractAvbPublicKey(signing_key) | 
 | 546 |         print("    Rewriting AVB public key of system_other in /product") | 
 | 547 |         common.ZipWrite(output_tf_zip, public_key, filename) | 
 | 548 |  | 
| Bowgo Tsai | 08aca59 | 2019-04-23 12:28:44 +0800 | [diff] [blame] | 549 |     # Should NOT sign boot-debug.img. | 
 | 550 |     elif filename in ( | 
 | 551 |         "BOOT/RAMDISK/force_debuggable", | 
 | 552 |         "RECOVERY/RAMDISK/force_debuggable" | 
 | 553 |         "RECOVERY/RAMDISK/first_stage_ramdisk/force_debuggable"): | 
 | 554 |       raise common.ExternalError("debuggable boot.img cannot be signed") | 
 | 555 |  | 
| Tao Bao | a80ed22 | 2016-06-16 14:41:24 -0700 | [diff] [blame] | 556 |     # A non-APK file; copy it verbatim. | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 557 |     else: | 
| Tao Bao | 2ed665a | 2015-04-01 11:21:55 -0700 | [diff] [blame] | 558 |       common.ZipWriteStr(output_tf_zip, out_info, data) | 
| Doug Zongker | 8e931bf | 2009-04-06 15:21:45 -0700 | [diff] [blame] | 559 |  | 
| Doug Zongker | 412c02f | 2014-02-13 10:58:24 -0800 | [diff] [blame] | 560 |   if OPTIONS.replace_ota_keys: | 
| Tianjie Xu | 616fbeb | 2017-05-23 14:51:02 -0700 | [diff] [blame] | 561 |     ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info) | 
| Doug Zongker | 412c02f | 2014-02-13 10:58:24 -0800 | [diff] [blame] | 562 |  | 
| Tao Bao | 46a5999 | 2017-06-05 11:55:16 -0700 | [diff] [blame] | 563 |   # Replace the keyid string in misc_info dict. | 
| Tao Bao | 8adcfd1 | 2016-06-17 17:01:22 -0700 | [diff] [blame] | 564 |   if OPTIONS.replace_verity_private_key: | 
| Tao Bao | 46a5999 | 2017-06-05 11:55:16 -0700 | [diff] [blame] | 565 |     ReplaceVerityPrivateKey(misc_info, OPTIONS.replace_verity_private_key[1]) | 
| Tao Bao | 8adcfd1 | 2016-06-17 17:01:22 -0700 | [diff] [blame] | 566 |  | 
 | 567 |   if OPTIONS.replace_verity_public_key: | 
| Tao Bao | 0c28d2d | 2017-12-24 10:37:38 -0800 | [diff] [blame] | 568 |     dest = "ROOT/verity_key" if system_root_image else "BOOT/RAMDISK/verity_key" | 
| Tao Bao | 8adcfd1 | 2016-06-17 17:01:22 -0700 | [diff] [blame] | 569 |     # We are replacing the one in boot image only, since the one under | 
 | 570 |     # recovery won't ever be needed. | 
| Tianjie Xu | 616fbeb | 2017-05-23 14:51:02 -0700 | [diff] [blame] | 571 |     ReplaceVerityPublicKey( | 
| Tao Bao | 8adcfd1 | 2016-06-17 17:01:22 -0700 | [diff] [blame] | 572 |         output_tf_zip, dest, OPTIONS.replace_verity_public_key[1]) | 
| Tao Bao | 8adcfd1 | 2016-06-17 17:01:22 -0700 | [diff] [blame] | 573 |  | 
 | 574 |   # Replace the keyid string in BOOT/cmdline. | 
 | 575 |   if OPTIONS.replace_verity_keyid: | 
| Tianjie Xu | 616fbeb | 2017-05-23 14:51:02 -0700 | [diff] [blame] | 576 |     ReplaceVerityKeyId(input_tf_zip, output_tf_zip, | 
 | 577 |                        OPTIONS.replace_verity_keyid[1]) | 
| Doug Zongker | 412c02f | 2014-02-13 10:58:24 -0800 | [diff] [blame] | 578 |  | 
| Tao Bao | 639118f | 2017-06-19 15:48:02 -0700 | [diff] [blame] | 579 |   # Replace the AVB signing keys, if any. | 
 | 580 |   ReplaceAvbSigningKeys(misc_info) | 
 | 581 |  | 
| Tao Bao | 46a5999 | 2017-06-05 11:55:16 -0700 | [diff] [blame] | 582 |   # Write back misc_info with the latest values. | 
 | 583 |   ReplaceMiscInfoTxt(input_tf_zip, output_tf_zip, misc_info) | 
 | 584 |  | 
| Doug Zongker | 8e931bf | 2009-04-06 15:21:45 -0700 | [diff] [blame] | 585 |  | 
| Robert Craig | 817c574 | 2013-04-19 10:59:22 -0400 | [diff] [blame] | 586 | def ReplaceCerts(data): | 
| Tao Bao | 6647263 | 2017-12-04 17:16:36 -0800 | [diff] [blame] | 587 |   """Replaces all the occurences of X.509 certs with the new ones. | 
| Robert Craig | 817c574 | 2013-04-19 10:59:22 -0400 | [diff] [blame] | 588 |  | 
| Tao Bao | 6647263 | 2017-12-04 17:16:36 -0800 | [diff] [blame] | 589 |   The mapping info is read from OPTIONS.key_map. Non-existent certificate will | 
 | 590 |   be skipped. After the replacement, it additionally checks for duplicate | 
 | 591 |   entries, which would otherwise fail the policy loading code in | 
 | 592 |   frameworks/base/services/core/java/com/android/server/pm/SELinuxMMAC.java. | 
 | 593 |  | 
 | 594 |   Args: | 
 | 595 |     data: Input string that contains a set of X.509 certs. | 
 | 596 |  | 
 | 597 |   Returns: | 
 | 598 |     A string after the replacement. | 
 | 599 |  | 
 | 600 |   Raises: | 
 | 601 |     AssertionError: On finding duplicate entries. | 
 | 602 |   """ | 
 | 603 |   for old, new in OPTIONS.key_map.iteritems(): | 
 | 604 |     if OPTIONS.verbose: | 
 | 605 |       print("    Replacing %s.x509.pem with %s.x509.pem" % (old, new)) | 
 | 606 |  | 
 | 607 |     try: | 
 | 608 |       with open(old + ".x509.pem") as old_fp: | 
 | 609 |         old_cert16 = base64.b16encode( | 
 | 610 |             common.ParseCertificate(old_fp.read())).lower() | 
 | 611 |       with open(new + ".x509.pem") as new_fp: | 
 | 612 |         new_cert16 = base64.b16encode( | 
 | 613 |             common.ParseCertificate(new_fp.read())).lower() | 
 | 614 |     except IOError as e: | 
 | 615 |       if OPTIONS.verbose or e.errno != errno.ENOENT: | 
 | 616 |         print("    Error accessing %s: %s.\nSkip replacing %s.x509.pem with " | 
 | 617 |               "%s.x509.pem." % (e.filename, e.strerror, old, new)) | 
 | 618 |       continue | 
 | 619 |  | 
 | 620 |     # Only match entire certs. | 
 | 621 |     pattern = "\\b" + old_cert16 + "\\b" | 
 | 622 |     (data, num) = re.subn(pattern, new_cert16, data, flags=re.IGNORECASE) | 
 | 623 |  | 
 | 624 |     if OPTIONS.verbose: | 
 | 625 |       print("    Replaced %d occurence(s) of %s.x509.pem with %s.x509.pem" % ( | 
 | 626 |           num, old, new)) | 
 | 627 |  | 
 | 628 |   # Verify that there're no duplicate entries after the replacement. Note that | 
 | 629 |   # it's only checking entries with global seinfo at the moment (i.e. ignoring | 
 | 630 |   # the ones with inner packages). (Bug: 69479366) | 
 | 631 |   root = ElementTree.fromstring(data) | 
 | 632 |   signatures = [signer.attrib['signature'] for signer in root.findall('signer')] | 
 | 633 |   assert len(signatures) == len(set(signatures)), \ | 
 | 634 |       "Found duplicate entries after cert replacement: {}".format(data) | 
| Robert Craig | 817c574 | 2013-04-19 10:59:22 -0400 | [diff] [blame] | 635 |  | 
 | 636 |   return data | 
 | 637 |  | 
 | 638 |  | 
| Doug Zongker | c09abc8 | 2010-01-11 13:09:15 -0800 | [diff] [blame] | 639 | def EditTags(tags): | 
| Tao Bao | a7054ee | 2017-12-08 14:42:16 -0800 | [diff] [blame] | 640 |   """Applies the edits to the tag string as specified in OPTIONS.tag_changes. | 
 | 641 |  | 
 | 642 |   Args: | 
 | 643 |     tags: The input string that contains comma-separated tags. | 
 | 644 |  | 
 | 645 |   Returns: | 
 | 646 |     The updated tags (comma-separated and sorted). | 
 | 647 |   """ | 
| Doug Zongker | c09abc8 | 2010-01-11 13:09:15 -0800 | [diff] [blame] | 648 |   tags = set(tags.split(",")) | 
 | 649 |   for ch in OPTIONS.tag_changes: | 
 | 650 |     if ch[0] == "-": | 
 | 651 |       tags.discard(ch[1:]) | 
 | 652 |     elif ch[0] == "+": | 
 | 653 |       tags.add(ch[1:]) | 
 | 654 |   return ",".join(sorted(tags)) | 
 | 655 |  | 
 | 656 |  | 
| Tao Bao | a7054ee | 2017-12-08 14:42:16 -0800 | [diff] [blame] | 657 | def RewriteProps(data): | 
 | 658 |   """Rewrites the system properties in the given string. | 
 | 659 |  | 
 | 660 |   Each property is expected in 'key=value' format. The properties that contain | 
 | 661 |   build tags (i.e. test-keys, dev-keys) will be updated accordingly by calling | 
 | 662 |   EditTags(). | 
 | 663 |  | 
 | 664 |   Args: | 
 | 665 |     data: Input string, separated by newlines. | 
 | 666 |  | 
 | 667 |   Returns: | 
 | 668 |     The string with modified properties. | 
 | 669 |   """ | 
| Doug Zongker | 17aa944 | 2009-04-17 10:15:58 -0700 | [diff] [blame] | 670 |   output = [] | 
 | 671 |   for line in data.split("\n"): | 
 | 672 |     line = line.strip() | 
 | 673 |     original_line = line | 
| Michael Runge | dc2661a | 2014-06-03 14:43:11 -0700 | [diff] [blame] | 674 |     if line and line[0] != '#' and "=" in line: | 
| Doug Zongker | 17aa944 | 2009-04-17 10:15:58 -0700 | [diff] [blame] | 675 |       key, value = line.split("=", 1) | 
| Magnus Strandh | 6396797 | 2019-05-01 23:09:30 +0200 | [diff] [blame] | 676 |       if (key.startswith("ro.") and | 
 | 677 |           key.endswith((".build.fingerprint", ".build.thumbprint"))): | 
| Doug Zongker | c09abc8 | 2010-01-11 13:09:15 -0800 | [diff] [blame] | 678 |         pieces = value.split("/") | 
 | 679 |         pieces[-1] = EditTags(pieces[-1]) | 
 | 680 |         value = "/".join(pieces) | 
| Tao Bao | cb7ff77 | 2015-09-11 15:27:56 -0700 | [diff] [blame] | 681 |       elif key == "ro.bootimage.build.fingerprint": | 
 | 682 |         pieces = value.split("/") | 
 | 683 |         pieces[-1] = EditTags(pieces[-1]) | 
 | 684 |         value = "/".join(pieces) | 
| Doug Zongker | 17aa944 | 2009-04-17 10:15:58 -0700 | [diff] [blame] | 685 |       elif key == "ro.build.description": | 
| Doug Zongker | c09abc8 | 2010-01-11 13:09:15 -0800 | [diff] [blame] | 686 |         pieces = value.split(" ") | 
| Doug Zongker | 17aa944 | 2009-04-17 10:15:58 -0700 | [diff] [blame] | 687 |         assert len(pieces) == 5 | 
| Doug Zongker | c09abc8 | 2010-01-11 13:09:15 -0800 | [diff] [blame] | 688 |         pieces[-1] = EditTags(pieces[-1]) | 
 | 689 |         value = " ".join(pieces) | 
| Magnus Strandh | 6396797 | 2019-05-01 23:09:30 +0200 | [diff] [blame] | 690 |       elif key.startswith("ro.") and key.endswith(".build.tags"): | 
| Doug Zongker | c09abc8 | 2010-01-11 13:09:15 -0800 | [diff] [blame] | 691 |         value = EditTags(value) | 
| Doug Zongker | a8608a7 | 2013-07-23 11:51:04 -0700 | [diff] [blame] | 692 |       elif key == "ro.build.display.id": | 
 | 693 |         # change, eg, "JWR66N dev-keys" to "JWR66N" | 
 | 694 |         value = value.split() | 
| Michael Runge | dc2661a | 2014-06-03 14:43:11 -0700 | [diff] [blame] | 695 |         if len(value) > 1 and value[-1].endswith("-keys"): | 
| Andrew Boie | 73d5abb | 2013-12-11 12:42:03 -0800 | [diff] [blame] | 696 |           value.pop() | 
 | 697 |         value = " ".join(value) | 
| Doug Zongker | c09abc8 | 2010-01-11 13:09:15 -0800 | [diff] [blame] | 698 |       line = key + "=" + value | 
| Doug Zongker | 17aa944 | 2009-04-17 10:15:58 -0700 | [diff] [blame] | 699 |     if line != original_line: | 
| Tao Bao | 0c28d2d | 2017-12-24 10:37:38 -0800 | [diff] [blame] | 700 |       print("  replace: ", original_line) | 
 | 701 |       print("     with: ", line) | 
| Doug Zongker | 17aa944 | 2009-04-17 10:15:58 -0700 | [diff] [blame] | 702 |     output.append(line) | 
 | 703 |   return "\n".join(output) + "\n" | 
 | 704 |  | 
 | 705 |  | 
| Tianjie Xu | ffbe6b9 | 2018-10-19 14:34:15 -0700 | [diff] [blame] | 706 | def WriteOtacerts(output_zip, filename, keys): | 
 | 707 |   """Constructs a zipfile from given keys; and writes it to output_zip. | 
 | 708 |  | 
 | 709 |   Args: | 
 | 710 |     output_zip: The output target_files zip. | 
 | 711 |     filename: The archive name in the output zip. | 
 | 712 |     keys: A list of public keys to use during OTA package verification. | 
 | 713 |   """ | 
 | 714 |  | 
 | 715 |   try: | 
 | 716 |     from StringIO import StringIO | 
 | 717 |   except ImportError: | 
 | 718 |     from io import StringIO | 
 | 719 |   temp_file = StringIO() | 
 | 720 |   certs_zip = zipfile.ZipFile(temp_file, "w") | 
 | 721 |   for k in keys: | 
 | 722 |     common.ZipWrite(certs_zip, k) | 
 | 723 |   common.ZipClose(certs_zip) | 
 | 724 |   common.ZipWriteStr(output_zip, filename, temp_file.getvalue()) | 
 | 725 |  | 
 | 726 |  | 
| Doug Zongker | 831840e | 2011-09-22 10:28:04 -0700 | [diff] [blame] | 727 | def ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info): | 
| Doug Zongker | 8e931bf | 2009-04-06 15:21:45 -0700 | [diff] [blame] | 728 |   try: | 
 | 729 |     keylist = input_tf_zip.read("META/otakeys.txt").split() | 
 | 730 |   except KeyError: | 
| T.R. Fullhart | a28acc6 | 2013-03-18 10:31:26 -0700 | [diff] [blame] | 731 |     raise common.ExternalError("can't read META/otakeys.txt from input") | 
| Doug Zongker | 8e931bf | 2009-04-06 15:21:45 -0700 | [diff] [blame] | 732 |  | 
| Tao Bao | f718f90 | 2017-11-09 10:10:10 -0800 | [diff] [blame] | 733 |   extra_recovery_keys = misc_info.get("extra_recovery_keys") | 
| Doug Zongker | e121d6a | 2011-02-01 14:13:52 -0800 | [diff] [blame] | 734 |   if extra_recovery_keys: | 
 | 735 |     extra_recovery_keys = [OPTIONS.key_map.get(k, k) + ".x509.pem" | 
 | 736 |                            for k in extra_recovery_keys.split()] | 
 | 737 |     if extra_recovery_keys: | 
| Tao Bao | 0c28d2d | 2017-12-24 10:37:38 -0800 | [diff] [blame] | 738 |       print("extra recovery-only key(s): " + ", ".join(extra_recovery_keys)) | 
| Doug Zongker | e121d6a | 2011-02-01 14:13:52 -0800 | [diff] [blame] | 739 |   else: | 
 | 740 |     extra_recovery_keys = [] | 
 | 741 |  | 
| Doug Zongker | 8e931bf | 2009-04-06 15:21:45 -0700 | [diff] [blame] | 742 |   mapped_keys = [] | 
 | 743 |   for k in keylist: | 
 | 744 |     m = re.match(r"^(.*)\.x509\.pem$", k) | 
 | 745 |     if not m: | 
| Doug Zongker | 412c02f | 2014-02-13 10:58:24 -0800 | [diff] [blame] | 746 |       raise common.ExternalError( | 
 | 747 |           "can't parse \"%s\" from META/otakeys.txt" % (k,)) | 
| Doug Zongker | 8e931bf | 2009-04-06 15:21:45 -0700 | [diff] [blame] | 748 |     k = m.group(1) | 
 | 749 |     mapped_keys.append(OPTIONS.key_map.get(k, k) + ".x509.pem") | 
 | 750 |  | 
| Doug Zongker | e05628c | 2009-08-20 17:38:42 -0700 | [diff] [blame] | 751 |   if mapped_keys: | 
| Tao Bao | 0c28d2d | 2017-12-24 10:37:38 -0800 | [diff] [blame] | 752 |     print("using:\n   ", "\n   ".join(mapped_keys)) | 
 | 753 |     print("for OTA package verification") | 
| Doug Zongker | e05628c | 2009-08-20 17:38:42 -0700 | [diff] [blame] | 754 |   else: | 
| Doug Zongker | 831840e | 2011-09-22 10:28:04 -0700 | [diff] [blame] | 755 |     devkey = misc_info.get("default_system_dev_certificate", | 
 | 756 |                            "build/target/product/security/testkey") | 
| Tao Bao | f718f90 | 2017-11-09 10:10:10 -0800 | [diff] [blame] | 757 |     mapped_devkey = OPTIONS.key_map.get(devkey, devkey) | 
 | 758 |     if mapped_devkey != devkey: | 
 | 759 |       misc_info["default_system_dev_certificate"] = mapped_devkey | 
 | 760 |     mapped_keys.append(mapped_devkey + ".x509.pem") | 
| Tao Bao | a80ed22 | 2016-06-16 14:41:24 -0700 | [diff] [blame] | 761 |     print("META/otakeys.txt has no keys; using %s for OTA package" | 
 | 762 |           " verification." % (mapped_keys[0],)) | 
| Doug Zongker | 8e931bf | 2009-04-06 15:21:45 -0700 | [diff] [blame] | 763 |  | 
| Tianjie Xu | ffbe6b9 | 2018-10-19 14:34:15 -0700 | [diff] [blame] | 764 |   # recovery now uses the same x509.pem version of the keys. | 
| Doug Zongker | e121d6a | 2011-02-01 14:13:52 -0800 | [diff] [blame] | 765 |   # extra_recovery_keys are used only in recovery. | 
| Tom Cherry | 2929cad | 2018-09-20 11:04:37 -0700 | [diff] [blame] | 766 |   if misc_info.get("recovery_as_boot") == "true": | 
| Tianjie Xu | ffbe6b9 | 2018-10-19 14:34:15 -0700 | [diff] [blame] | 767 |     recovery_keys_location = "BOOT/RAMDISK/system/etc/security/otacerts.zip" | 
| Tao Bao | a80ed22 | 2016-06-16 14:41:24 -0700 | [diff] [blame] | 768 |   else: | 
| Tianjie Xu | ffbe6b9 | 2018-10-19 14:34:15 -0700 | [diff] [blame] | 769 |     recovery_keys_location = "RECOVERY/RAMDISK/system/etc/security/otacerts.zip" | 
 | 770 |  | 
 | 771 |   WriteOtacerts(output_tf_zip, recovery_keys_location, | 
 | 772 |                 mapped_keys + extra_recovery_keys) | 
| Doug Zongker | 8e931bf | 2009-04-06 15:21:45 -0700 | [diff] [blame] | 773 |  | 
 | 774 |   # SystemUpdateActivity uses the x509.pem version of the keys, but | 
 | 775 |   # put into a zipfile system/etc/security/otacerts.zip. | 
| Doug Zongker | e121d6a | 2011-02-01 14:13:52 -0800 | [diff] [blame] | 776 |   # We DO NOT include the extra_recovery_keys (if any) here. | 
| Tianjie Xu | ffbe6b9 | 2018-10-19 14:34:15 -0700 | [diff] [blame] | 777 |   WriteOtacerts(output_tf_zip, "SYSTEM/etc/security/otacerts.zip", mapped_keys) | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 778 |  | 
| Tao Bao | a80ed22 | 2016-06-16 14:41:24 -0700 | [diff] [blame] | 779 |   # For A/B devices, update the payload verification key. | 
 | 780 |   if misc_info.get("ab_update") == "true": | 
 | 781 |     # Unlike otacerts.zip that may contain multiple keys, we can only specify | 
 | 782 |     # ONE payload verification key. | 
 | 783 |     if len(mapped_keys) > 1: | 
 | 784 |       print("\n  WARNING: Found more than one OTA keys; Using the first one" | 
 | 785 |             " as payload verification key.\n\n") | 
 | 786 |  | 
| Tao Bao | 0c28d2d | 2017-12-24 10:37:38 -0800 | [diff] [blame] | 787 |     print("Using %s for payload verification." % (mapped_keys[0],)) | 
| Tao Bao | 04e1f01 | 2018-02-04 12:13:35 -0800 | [diff] [blame] | 788 |     pubkey = common.ExtractPublicKey(mapped_keys[0]) | 
| Tao Bao | 13b6962 | 2016-07-06 15:28:59 -0700 | [diff] [blame] | 789 |     common.ZipWriteStr( | 
| Tao Bao | a80ed22 | 2016-06-16 14:41:24 -0700 | [diff] [blame] | 790 |         output_tf_zip, | 
| Tao Bao | 13b6962 | 2016-07-06 15:28:59 -0700 | [diff] [blame] | 791 |         "SYSTEM/etc/update_engine/update-payload-key.pub.pem", | 
 | 792 |         pubkey) | 
| Alex Deymo | b3e8ce6 | 2016-08-04 16:06:12 -0700 | [diff] [blame] | 793 |     common.ZipWriteStr( | 
 | 794 |         output_tf_zip, | 
| Tao Bao | 696bb33 | 2018-08-17 16:27:01 -0700 | [diff] [blame] | 795 |         "BOOT/RAMDISK/system/etc/update_engine/update-payload-key.pub.pem", | 
| Alex Deymo | b3e8ce6 | 2016-08-04 16:06:12 -0700 | [diff] [blame] | 796 |         pubkey) | 
| Tao Bao | a80ed22 | 2016-06-16 14:41:24 -0700 | [diff] [blame] | 797 |  | 
| Tao Bao | 8adcfd1 | 2016-06-17 17:01:22 -0700 | [diff] [blame] | 798 |  | 
| Tao Bao | 0c28d2d | 2017-12-24 10:37:38 -0800 | [diff] [blame] | 799 | def ReplaceVerityPublicKey(output_zip, filename, key_path): | 
 | 800 |   """Replaces the verity public key at the given path in the given zip. | 
 | 801 |  | 
 | 802 |   Args: | 
 | 803 |     output_zip: The output target_files zip. | 
 | 804 |     filename: The archive name in the output zip. | 
 | 805 |     key_path: The path to the public key. | 
 | 806 |   """ | 
 | 807 |   print("Replacing verity public key with %s" % (key_path,)) | 
 | 808 |   common.ZipWrite(output_zip, key_path, arcname=filename) | 
| Geremy Condra | f19b365 | 2014-07-29 17:54:54 -0700 | [diff] [blame] | 809 |  | 
| Tao Bao | 8adcfd1 | 2016-06-17 17:01:22 -0700 | [diff] [blame] | 810 |  | 
| Tao Bao | 46a5999 | 2017-06-05 11:55:16 -0700 | [diff] [blame] | 811 | def ReplaceVerityPrivateKey(misc_info, key_path): | 
| Tao Bao | 0c28d2d | 2017-12-24 10:37:38 -0800 | [diff] [blame] | 812 |   """Replaces the verity private key in misc_info dict. | 
 | 813 |  | 
 | 814 |   Args: | 
 | 815 |     misc_info: The info dict. | 
 | 816 |     key_path: The path to the private key in PKCS#8 format. | 
 | 817 |   """ | 
 | 818 |   print("Replacing verity private key with %s" % (key_path,)) | 
| Andrew Boie | d083f0b | 2014-09-15 16:01:07 -0700 | [diff] [blame] | 819 |   misc_info["verity_key"] = key_path | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 820 |  | 
| Tao Bao | 8adcfd1 | 2016-06-17 17:01:22 -0700 | [diff] [blame] | 821 |  | 
| Tao Bao | e838d14 | 2017-12-23 23:44:48 -0800 | [diff] [blame] | 822 | def ReplaceVerityKeyId(input_zip, output_zip, key_path): | 
 | 823 |   """Replaces the veritykeyid parameter in BOOT/cmdline. | 
 | 824 |  | 
 | 825 |   Args: | 
 | 826 |     input_zip: The input target_files zip, which should be already open. | 
 | 827 |     output_zip: The output target_files zip, which should be already open and | 
 | 828 |         writable. | 
 | 829 |     key_path: The path to the PEM encoded X.509 certificate. | 
 | 830 |   """ | 
 | 831 |   in_cmdline = input_zip.read("BOOT/cmdline") | 
 | 832 |   # Copy in_cmdline to output_zip if veritykeyid is not present. | 
| Badhri Jagan Sridharan | 35c9b12 | 2016-06-16 19:58:44 -0700 | [diff] [blame] | 833 |   if "veritykeyid" not in in_cmdline: | 
| Tao Bao | e838d14 | 2017-12-23 23:44:48 -0800 | [diff] [blame] | 834 |     common.ZipWriteStr(output_zip, "BOOT/cmdline", in_cmdline) | 
 | 835 |     return | 
 | 836 |  | 
| Tao Bao | 0c28d2d | 2017-12-24 10:37:38 -0800 | [diff] [blame] | 837 |   out_buffer = [] | 
| Badhri Jagan Sridharan | 35c9b12 | 2016-06-16 19:58:44 -0700 | [diff] [blame] | 838 |   for param in in_cmdline.split(): | 
| Tao Bao | e838d14 | 2017-12-23 23:44:48 -0800 | [diff] [blame] | 839 |     if "veritykeyid" not in param: | 
| Tao Bao | 0c28d2d | 2017-12-24 10:37:38 -0800 | [diff] [blame] | 840 |       out_buffer.append(param) | 
| Tao Bao | e838d14 | 2017-12-23 23:44:48 -0800 | [diff] [blame] | 841 |       continue | 
| Badhri Jagan Sridharan | 35c9b12 | 2016-06-16 19:58:44 -0700 | [diff] [blame] | 842 |  | 
| Tao Bao | e838d14 | 2017-12-23 23:44:48 -0800 | [diff] [blame] | 843 |     # Extract keyid using openssl command. | 
 | 844 |     p = common.Run(["openssl", "x509", "-in", key_path, "-text"], | 
| Tao Bao | de1d479 | 2018-02-20 10:05:46 -0800 | [diff] [blame] | 845 |                    stdout=subprocess.PIPE, stderr=subprocess.PIPE) | 
| Tao Bao | e838d14 | 2017-12-23 23:44:48 -0800 | [diff] [blame] | 846 |     keyid, stderr = p.communicate() | 
 | 847 |     assert p.returncode == 0, "Failed to dump certificate: {}".format(stderr) | 
 | 848 |     keyid = re.search( | 
 | 849 |         r'keyid:([0-9a-fA-F:]*)', keyid).group(1).replace(':', '').lower() | 
 | 850 |     print("Replacing verity keyid with {}".format(keyid)) | 
 | 851 |     out_buffer.append("veritykeyid=id:%s" % (keyid,)) | 
 | 852 |  | 
 | 853 |   out_cmdline = ' '.join(out_buffer).strip() + '\n' | 
 | 854 |   common.ZipWriteStr(output_zip, "BOOT/cmdline", out_cmdline) | 
| Tao Bao | 46a5999 | 2017-06-05 11:55:16 -0700 | [diff] [blame] | 855 |  | 
 | 856 |  | 
 | 857 | def ReplaceMiscInfoTxt(input_zip, output_zip, misc_info): | 
 | 858 |   """Replaces META/misc_info.txt. | 
 | 859 |  | 
 | 860 |   Only writes back the ones in the original META/misc_info.txt. Because the | 
 | 861 |   current in-memory dict contains additional items computed at runtime. | 
 | 862 |   """ | 
 | 863 |   misc_info_old = common.LoadDictionaryFromLines( | 
 | 864 |       input_zip.read('META/misc_info.txt').split('\n')) | 
 | 865 |   items = [] | 
 | 866 |   for key in sorted(misc_info): | 
 | 867 |     if key in misc_info_old: | 
 | 868 |       items.append('%s=%s' % (key, misc_info[key])) | 
 | 869 |   common.ZipWriteStr(output_zip, "META/misc_info.txt", '\n'.join(items)) | 
| Badhri Jagan Sridharan | 35c9b12 | 2016-06-16 19:58:44 -0700 | [diff] [blame] | 870 |  | 
| Tao Bao | 8adcfd1 | 2016-06-17 17:01:22 -0700 | [diff] [blame] | 871 |  | 
| Tao Bao | 639118f | 2017-06-19 15:48:02 -0700 | [diff] [blame] | 872 | def ReplaceAvbSigningKeys(misc_info): | 
 | 873 |   """Replaces the AVB signing keys.""" | 
 | 874 |  | 
 | 875 |   AVB_FOOTER_ARGS_BY_PARTITION = { | 
| Tao Bao | 0c28d2d | 2017-12-24 10:37:38 -0800 | [diff] [blame] | 876 |       'boot' : 'avb_boot_add_hash_footer_args', | 
 | 877 |       'dtbo' : 'avb_dtbo_add_hash_footer_args', | 
 | 878 |       'recovery' : 'avb_recovery_add_hash_footer_args', | 
 | 879 |       'system' : 'avb_system_add_hashtree_footer_args', | 
| Bowgo Tsai | e4544b1 | 2019-02-27 10:15:51 +0800 | [diff] [blame] | 880 |       'system_other' : 'avb_system_other_add_hashtree_footer_args', | 
| Tao Bao | 0c28d2d | 2017-12-24 10:37:38 -0800 | [diff] [blame] | 881 |       'vendor' : 'avb_vendor_add_hashtree_footer_args', | 
 | 882 |       'vbmeta' : 'avb_vbmeta_args', | 
| Tao Bao | d403e7b | 2019-05-06 12:55:42 -0700 | [diff] [blame] | 883 |       'vbmeta_system' : 'avb_vbmeta_system_args', | 
 | 884 |       'vbmeta_vendor' : 'avb_vbmeta_vendor_args', | 
| Tao Bao | 639118f | 2017-06-19 15:48:02 -0700 | [diff] [blame] | 885 |   } | 
 | 886 |  | 
 | 887 |   def ReplaceAvbPartitionSigningKey(partition): | 
 | 888 |     key = OPTIONS.avb_keys.get(partition) | 
 | 889 |     if not key: | 
 | 890 |       return | 
 | 891 |  | 
 | 892 |     algorithm = OPTIONS.avb_algorithms.get(partition) | 
 | 893 |     assert algorithm, 'Missing AVB signing algorithm for %s' % (partition,) | 
 | 894 |  | 
| Tao Bao | 0c28d2d | 2017-12-24 10:37:38 -0800 | [diff] [blame] | 895 |     print('Replacing AVB signing key for %s with "%s" (%s)' % ( | 
 | 896 |         partition, key, algorithm)) | 
| Tao Bao | 639118f | 2017-06-19 15:48:02 -0700 | [diff] [blame] | 897 |     misc_info['avb_' + partition + '_algorithm'] = algorithm | 
 | 898 |     misc_info['avb_' + partition + '_key_path'] = key | 
 | 899 |  | 
 | 900 |     extra_args = OPTIONS.avb_extra_args.get(partition) | 
 | 901 |     if extra_args: | 
| Tao Bao | 0c28d2d | 2017-12-24 10:37:38 -0800 | [diff] [blame] | 902 |       print('Setting extra AVB signing args for %s to "%s"' % ( | 
 | 903 |           partition, extra_args)) | 
| Tao Bao | 639118f | 2017-06-19 15:48:02 -0700 | [diff] [blame] | 904 |       args_key = AVB_FOOTER_ARGS_BY_PARTITION[partition] | 
 | 905 |       misc_info[args_key] = (misc_info.get(args_key, '') + ' ' + extra_args) | 
 | 906 |  | 
 | 907 |   for partition in AVB_FOOTER_ARGS_BY_PARTITION: | 
 | 908 |     ReplaceAvbPartitionSigningKey(partition) | 
 | 909 |  | 
 | 910 |  | 
| Doug Zongker | 831840e | 2011-09-22 10:28:04 -0700 | [diff] [blame] | 911 | def BuildKeyMap(misc_info, key_mapping_options): | 
 | 912 |   for s, d in key_mapping_options: | 
 | 913 |     if s is None:   # -d option | 
 | 914 |       devkey = misc_info.get("default_system_dev_certificate", | 
 | 915 |                              "build/target/product/security/testkey") | 
 | 916 |       devkeydir = os.path.dirname(devkey) | 
 | 917 |  | 
 | 918 |       OPTIONS.key_map.update({ | 
 | 919 |           devkeydir + "/testkey":  d + "/releasekey", | 
 | 920 |           devkeydir + "/devkey":   d + "/releasekey", | 
 | 921 |           devkeydir + "/media":    d + "/media", | 
 | 922 |           devkeydir + "/shared":   d + "/shared", | 
 | 923 |           devkeydir + "/platform": d + "/platform", | 
 | 924 |           }) | 
 | 925 |     else: | 
 | 926 |       OPTIONS.key_map[s] = d | 
 | 927 |  | 
 | 928 |  | 
| Alex Klyubin | 2cfd1d1 | 2016-01-13 10:32:47 -0800 | [diff] [blame] | 929 | def GetApiLevelAndCodename(input_tf_zip): | 
 | 930 |   data = input_tf_zip.read("SYSTEM/build.prop") | 
 | 931 |   api_level = None | 
 | 932 |   codename = None | 
 | 933 |   for line in data.split("\n"): | 
 | 934 |     line = line.strip() | 
| Alex Klyubin | 2cfd1d1 | 2016-01-13 10:32:47 -0800 | [diff] [blame] | 935 |     if line and line[0] != '#' and "=" in line: | 
 | 936 |       key, value = line.split("=", 1) | 
 | 937 |       key = key.strip() | 
 | 938 |       if key == "ro.build.version.sdk": | 
 | 939 |         api_level = int(value.strip()) | 
 | 940 |       elif key == "ro.build.version.codename": | 
 | 941 |         codename = value.strip() | 
 | 942 |  | 
 | 943 |   if api_level is None: | 
 | 944 |     raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop") | 
 | 945 |   if codename is None: | 
 | 946 |     raise ValueError("No ro.build.version.codename in SYSTEM/build.prop") | 
 | 947 |  | 
 | 948 |   return (api_level, codename) | 
 | 949 |  | 
 | 950 |  | 
 | 951 | def GetCodenameToApiLevelMap(input_tf_zip): | 
 | 952 |   data = input_tf_zip.read("SYSTEM/build.prop") | 
 | 953 |   api_level = None | 
 | 954 |   codenames = None | 
 | 955 |   for line in data.split("\n"): | 
 | 956 |     line = line.strip() | 
| Alex Klyubin | 2cfd1d1 | 2016-01-13 10:32:47 -0800 | [diff] [blame] | 957 |     if line and line[0] != '#' and "=" in line: | 
 | 958 |       key, value = line.split("=", 1) | 
 | 959 |       key = key.strip() | 
 | 960 |       if key == "ro.build.version.sdk": | 
 | 961 |         api_level = int(value.strip()) | 
 | 962 |       elif key == "ro.build.version.all_codenames": | 
 | 963 |         codenames = value.strip().split(",") | 
 | 964 |  | 
 | 965 |   if api_level is None: | 
 | 966 |     raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop") | 
 | 967 |   if codenames is None: | 
 | 968 |     raise ValueError("No ro.build.version.all_codenames in SYSTEM/build.prop") | 
 | 969 |  | 
 | 970 |   result = dict() | 
 | 971 |   for codename in codenames: | 
 | 972 |     codename = codename.strip() | 
| Tao Bao | badceb2 | 2019-03-15 09:33:43 -0700 | [diff] [blame] | 973 |     if codename: | 
| Alex Klyubin | 2cfd1d1 | 2016-01-13 10:32:47 -0800 | [diff] [blame] | 974 |       result[codename] = api_level | 
| Tao Bao | 9e401df | 2019-06-03 13:57:09 -0700 | [diff] [blame] | 975 |  | 
 | 976 |   # Work around APKs that still target 'Q' instead of API 29 (b/132882632). | 
 | 977 |   result['Q'] = 29 | 
 | 978 |  | 
| Alex Klyubin | 2cfd1d1 | 2016-01-13 10:32:47 -0800 | [diff] [blame] | 979 |   return result | 
 | 980 |  | 
 | 981 |  | 
| Tao Bao | aa7e993 | 2019-03-15 09:37:01 -0700 | [diff] [blame] | 982 | def ReadApexKeysInfo(tf_zip): | 
 | 983 |   """Parses the APEX keys info from a given target-files zip. | 
 | 984 |  | 
 | 985 |   Given a target-files ZipFile, parses the META/apexkeys.txt entry and returns a | 
 | 986 |   dict that contains the mapping from APEX names (e.g. com.android.tzdata) to a | 
 | 987 |   tuple of (payload_key, container_key). | 
 | 988 |  | 
 | 989 |   Args: | 
 | 990 |     tf_zip: The input target_files ZipFile (already open). | 
 | 991 |  | 
 | 992 |   Returns: | 
 | 993 |     (payload_key, container_key): payload_key contains the path to the payload | 
 | 994 |         signing key; container_key contains the path to the container signing | 
 | 995 |         key. | 
 | 996 |   """ | 
 | 997 |   keys = {} | 
 | 998 |   for line in tf_zip.read("META/apexkeys.txt").split("\n"): | 
 | 999 |     line = line.strip() | 
 | 1000 |     if not line: | 
 | 1001 |       continue | 
 | 1002 |     matches = re.match( | 
 | 1003 |         r'^name="(?P<NAME>.*)"\s+' | 
 | 1004 |         r'public_key="(?P<PAYLOAD_PUBLIC_KEY>.*)"\s+' | 
 | 1005 |         r'private_key="(?P<PAYLOAD_PRIVATE_KEY>.*)"\s+' | 
 | 1006 |         r'container_certificate="(?P<CONTAINER_CERT>.*)"\s+' | 
 | 1007 |         r'container_private_key="(?P<CONTAINER_PRIVATE_KEY>.*)"$', | 
 | 1008 |         line) | 
 | 1009 |     if not matches: | 
 | 1010 |       continue | 
 | 1011 |  | 
 | 1012 |     name = matches.group('NAME') | 
| Tao Bao | aa7e993 | 2019-03-15 09:37:01 -0700 | [diff] [blame] | 1013 |     payload_private_key = matches.group("PAYLOAD_PRIVATE_KEY") | 
 | 1014 |  | 
 | 1015 |     def CompareKeys(pubkey, pubkey_suffix, privkey, privkey_suffix): | 
 | 1016 |       pubkey_suffix_len = len(pubkey_suffix) | 
 | 1017 |       privkey_suffix_len = len(privkey_suffix) | 
 | 1018 |       return (pubkey.endswith(pubkey_suffix) and | 
 | 1019 |               privkey.endswith(privkey_suffix) and | 
 | 1020 |               pubkey[:-pubkey_suffix_len] == privkey[:-privkey_suffix_len]) | 
 | 1021 |  | 
| Tao Bao | 6d9e3da | 2019-03-26 12:59:25 -0700 | [diff] [blame] | 1022 |     # Sanity check on the container key names, as we'll carry them without the | 
 | 1023 |     # extensions. This doesn't apply to payload keys though, which we will use | 
 | 1024 |     # full names only. | 
| Tao Bao | aa7e993 | 2019-03-15 09:37:01 -0700 | [diff] [blame] | 1025 |     container_cert = matches.group("CONTAINER_CERT") | 
 | 1026 |     container_private_key = matches.group("CONTAINER_PRIVATE_KEY") | 
| Tao Bao | 548db7d | 2019-04-24 23:53:42 -0700 | [diff] [blame] | 1027 |     if container_cert == 'PRESIGNED' and container_private_key == 'PRESIGNED': | 
 | 1028 |       container_key = 'PRESIGNED' | 
 | 1029 |     elif CompareKeys( | 
| Tao Bao | aa7e993 | 2019-03-15 09:37:01 -0700 | [diff] [blame] | 1030 |         container_cert, OPTIONS.public_key_suffix, | 
 | 1031 |         container_private_key, OPTIONS.private_key_suffix): | 
| Tao Bao | 548db7d | 2019-04-24 23:53:42 -0700 | [diff] [blame] | 1032 |       container_key = container_cert[:-len(OPTIONS.public_key_suffix)] | 
 | 1033 |     else: | 
| Tao Bao | aa7e993 | 2019-03-15 09:37:01 -0700 | [diff] [blame] | 1034 |       raise ValueError("Failed to parse container keys: \n{}".format(line)) | 
 | 1035 |  | 
| Tao Bao | 548db7d | 2019-04-24 23:53:42 -0700 | [diff] [blame] | 1036 |     keys[name] = (payload_private_key, container_key) | 
| Tao Bao | aa7e993 | 2019-03-15 09:37:01 -0700 | [diff] [blame] | 1037 |  | 
 | 1038 |   return keys | 
 | 1039 |  | 
 | 1040 |  | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 1041 | def main(argv): | 
 | 1042 |  | 
| Doug Zongker | 831840e | 2011-09-22 10:28:04 -0700 | [diff] [blame] | 1043 |   key_mapping_options = [] | 
 | 1044 |  | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 1045 |   def option_handler(o, a): | 
| Doug Zongker | 05d3dea | 2009-06-22 11:32:31 -0700 | [diff] [blame] | 1046 |     if o in ("-e", "--extra_apks"): | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 1047 |       names, key = a.split("=") | 
 | 1048 |       names = names.split(",") | 
 | 1049 |       for n in names: | 
 | 1050 |         OPTIONS.extra_apks[n] = key | 
| Tao Bao | aa7e993 | 2019-03-15 09:37:01 -0700 | [diff] [blame] | 1051 |     elif o == "--extra_apex_payload_key": | 
 | 1052 |       apex_name, key = a.split("=") | 
 | 1053 |       OPTIONS.extra_apex_payload_keys[apex_name] = key | 
| Tao Bao | 93c2a01 | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 1054 |     elif o == "--skip_apks_with_path_prefix": | 
 | 1055 |       # Sanity check the prefix, which must be in all upper case. | 
 | 1056 |       prefix = a.split('/')[0] | 
 | 1057 |       if not prefix or prefix != prefix.upper(): | 
 | 1058 |         raise ValueError("Invalid path prefix '%s'" % (a,)) | 
 | 1059 |       OPTIONS.skip_apks_with_path_prefix.add(a) | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 1060 |     elif o in ("-d", "--default_key_mappings"): | 
| Doug Zongker | 831840e | 2011-09-22 10:28:04 -0700 | [diff] [blame] | 1061 |       key_mapping_options.append((None, a)) | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 1062 |     elif o in ("-k", "--key_mapping"): | 
| Doug Zongker | 831840e | 2011-09-22 10:28:04 -0700 | [diff] [blame] | 1063 |       key_mapping_options.append(a.split("=", 1)) | 
| Doug Zongker | 8e931bf | 2009-04-06 15:21:45 -0700 | [diff] [blame] | 1064 |     elif o in ("-o", "--replace_ota_keys"): | 
 | 1065 |       OPTIONS.replace_ota_keys = True | 
| Doug Zongker | ae87701 | 2009-04-21 10:04:51 -0700 | [diff] [blame] | 1066 |     elif o in ("-t", "--tag_changes"): | 
 | 1067 |       new = [] | 
 | 1068 |       for i in a.split(","): | 
 | 1069 |         i = i.strip() | 
 | 1070 |         if not i or i[0] not in "-+": | 
 | 1071 |           raise ValueError("Bad tag change '%s'" % (i,)) | 
 | 1072 |         new.append(i[0] + i[1:].strip()) | 
 | 1073 |       OPTIONS.tag_changes = tuple(new) | 
| Geremy Condra | f19b365 | 2014-07-29 17:54:54 -0700 | [diff] [blame] | 1074 |     elif o == "--replace_verity_public_key": | 
 | 1075 |       OPTIONS.replace_verity_public_key = (True, a) | 
 | 1076 |     elif o == "--replace_verity_private_key": | 
 | 1077 |       OPTIONS.replace_verity_private_key = (True, a) | 
| Badhri Jagan Sridharan | 35c9b12 | 2016-06-16 19:58:44 -0700 | [diff] [blame] | 1078 |     elif o == "--replace_verity_keyid": | 
 | 1079 |       OPTIONS.replace_verity_keyid = (True, a) | 
| Tao Bao | 639118f | 2017-06-19 15:48:02 -0700 | [diff] [blame] | 1080 |     elif o == "--avb_vbmeta_key": | 
 | 1081 |       OPTIONS.avb_keys['vbmeta'] = a | 
 | 1082 |     elif o == "--avb_vbmeta_algorithm": | 
 | 1083 |       OPTIONS.avb_algorithms['vbmeta'] = a | 
 | 1084 |     elif o == "--avb_vbmeta_extra_args": | 
 | 1085 |       OPTIONS.avb_extra_args['vbmeta'] = a | 
 | 1086 |     elif o == "--avb_boot_key": | 
 | 1087 |       OPTIONS.avb_keys['boot'] = a | 
 | 1088 |     elif o == "--avb_boot_algorithm": | 
 | 1089 |       OPTIONS.avb_algorithms['boot'] = a | 
 | 1090 |     elif o == "--avb_boot_extra_args": | 
 | 1091 |       OPTIONS.avb_extra_args['boot'] = a | 
 | 1092 |     elif o == "--avb_dtbo_key": | 
 | 1093 |       OPTIONS.avb_keys['dtbo'] = a | 
 | 1094 |     elif o == "--avb_dtbo_algorithm": | 
 | 1095 |       OPTIONS.avb_algorithms['dtbo'] = a | 
 | 1096 |     elif o == "--avb_dtbo_extra_args": | 
 | 1097 |       OPTIONS.avb_extra_args['dtbo'] = a | 
 | 1098 |     elif o == "--avb_system_key": | 
 | 1099 |       OPTIONS.avb_keys['system'] = a | 
 | 1100 |     elif o == "--avb_system_algorithm": | 
 | 1101 |       OPTIONS.avb_algorithms['system'] = a | 
 | 1102 |     elif o == "--avb_system_extra_args": | 
 | 1103 |       OPTIONS.avb_extra_args['system'] = a | 
| Bowgo Tsai | e4544b1 | 2019-02-27 10:15:51 +0800 | [diff] [blame] | 1104 |     elif o == "--avb_system_other_key": | 
 | 1105 |       OPTIONS.avb_keys['system_other'] = a | 
 | 1106 |     elif o == "--avb_system_other_algorithm": | 
 | 1107 |       OPTIONS.avb_algorithms['system_other'] = a | 
 | 1108 |     elif o == "--avb_system_other_extra_args": | 
 | 1109 |       OPTIONS.avb_extra_args['system_other'] = a | 
| Tao Bao | 639118f | 2017-06-19 15:48:02 -0700 | [diff] [blame] | 1110 |     elif o == "--avb_vendor_key": | 
 | 1111 |       OPTIONS.avb_keys['vendor'] = a | 
 | 1112 |     elif o == "--avb_vendor_algorithm": | 
 | 1113 |       OPTIONS.avb_algorithms['vendor'] = a | 
 | 1114 |     elif o == "--avb_vendor_extra_args": | 
 | 1115 |       OPTIONS.avb_extra_args['vendor'] = a | 
| Tao Bao | d403e7b | 2019-05-06 12:55:42 -0700 | [diff] [blame] | 1116 |     elif o == "--avb_vbmeta_system_key": | 
 | 1117 |       OPTIONS.avb_keys['vbmeta_system'] = a | 
 | 1118 |     elif o == "--avb_vbmeta_system_algorithm": | 
 | 1119 |       OPTIONS.avb_algorithms['vbmeta_system'] = a | 
 | 1120 |     elif o == "--avb_vbmeta_system_extra_args": | 
 | 1121 |       OPTIONS.avb_extra_args['vbmeta_system'] = a | 
 | 1122 |     elif o == "--avb_vbmeta_vendor_key": | 
 | 1123 |       OPTIONS.avb_keys['vbmeta_vendor'] = a | 
 | 1124 |     elif o == "--avb_vbmeta_vendor_algorithm": | 
 | 1125 |       OPTIONS.avb_algorithms['vbmeta_vendor'] = a | 
 | 1126 |     elif o == "--avb_vbmeta_vendor_extra_args": | 
 | 1127 |       OPTIONS.avb_extra_args['vbmeta_vendor'] = a | 
| Tao Bao | aa7e993 | 2019-03-15 09:37:01 -0700 | [diff] [blame] | 1128 |     elif o == "--avb_apex_extra_args": | 
 | 1129 |       OPTIONS.avb_extra_args['apex'] = a | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 1130 |     else: | 
 | 1131 |       return False | 
 | 1132 |     return True | 
 | 1133 |  | 
| Tao Bao | 639118f | 2017-06-19 15:48:02 -0700 | [diff] [blame] | 1134 |   args = common.ParseOptions( | 
 | 1135 |       argv, __doc__, | 
 | 1136 |       extra_opts="e:d:k:ot:", | 
 | 1137 |       extra_long_opts=[ | 
| Tao Bao | 0c28d2d | 2017-12-24 10:37:38 -0800 | [diff] [blame] | 1138 |           "extra_apks=", | 
| Tao Bao | aa7e993 | 2019-03-15 09:37:01 -0700 | [diff] [blame] | 1139 |           "extra_apex_payload_key=", | 
| Tao Bao | 93c2a01 | 2018-06-19 12:19:35 -0700 | [diff] [blame] | 1140 |           "skip_apks_with_path_prefix=", | 
| Tao Bao | 0c28d2d | 2017-12-24 10:37:38 -0800 | [diff] [blame] | 1141 |           "default_key_mappings=", | 
 | 1142 |           "key_mapping=", | 
 | 1143 |           "replace_ota_keys", | 
 | 1144 |           "tag_changes=", | 
 | 1145 |           "replace_verity_public_key=", | 
 | 1146 |           "replace_verity_private_key=", | 
 | 1147 |           "replace_verity_keyid=", | 
| Tao Bao | aa7e993 | 2019-03-15 09:37:01 -0700 | [diff] [blame] | 1148 |           "avb_apex_extra_args=", | 
| Tao Bao | 0c28d2d | 2017-12-24 10:37:38 -0800 | [diff] [blame] | 1149 |           "avb_vbmeta_algorithm=", | 
 | 1150 |           "avb_vbmeta_key=", | 
 | 1151 |           "avb_vbmeta_extra_args=", | 
 | 1152 |           "avb_boot_algorithm=", | 
 | 1153 |           "avb_boot_key=", | 
 | 1154 |           "avb_boot_extra_args=", | 
 | 1155 |           "avb_dtbo_algorithm=", | 
 | 1156 |           "avb_dtbo_key=", | 
 | 1157 |           "avb_dtbo_extra_args=", | 
 | 1158 |           "avb_system_algorithm=", | 
 | 1159 |           "avb_system_key=", | 
 | 1160 |           "avb_system_extra_args=", | 
| Bowgo Tsai | e4544b1 | 2019-02-27 10:15:51 +0800 | [diff] [blame] | 1161 |           "avb_system_other_algorithm=", | 
 | 1162 |           "avb_system_other_key=", | 
 | 1163 |           "avb_system_other_extra_args=", | 
| Tao Bao | 0c28d2d | 2017-12-24 10:37:38 -0800 | [diff] [blame] | 1164 |           "avb_vendor_algorithm=", | 
 | 1165 |           "avb_vendor_key=", | 
 | 1166 |           "avb_vendor_extra_args=", | 
| Tao Bao | d403e7b | 2019-05-06 12:55:42 -0700 | [diff] [blame] | 1167 |           "avb_vbmeta_system_algorithm=", | 
 | 1168 |           "avb_vbmeta_system_key=", | 
 | 1169 |           "avb_vbmeta_system_extra_args=", | 
 | 1170 |           "avb_vbmeta_vendor_algorithm=", | 
 | 1171 |           "avb_vbmeta_vendor_key=", | 
 | 1172 |           "avb_vbmeta_vendor_extra_args=", | 
| Tao Bao | 639118f | 2017-06-19 15:48:02 -0700 | [diff] [blame] | 1173 |       ], | 
 | 1174 |       extra_option_handler=option_handler) | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 1175 |  | 
 | 1176 |   if len(args) != 2: | 
 | 1177 |     common.Usage(__doc__) | 
 | 1178 |     sys.exit(1) | 
 | 1179 |  | 
| Tao Bao | badceb2 | 2019-03-15 09:33:43 -0700 | [diff] [blame] | 1180 |   common.InitLogging() | 
 | 1181 |  | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 1182 |   input_zip = zipfile.ZipFile(args[0], "r") | 
| Tao Bao | 2b8f489 | 2017-06-13 12:54:58 -0700 | [diff] [blame] | 1183 |   output_zip = zipfile.ZipFile(args[1], "w", | 
 | 1184 |                                compression=zipfile.ZIP_DEFLATED, | 
 | 1185 |                                allowZip64=True) | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 1186 |  | 
| Doug Zongker | 831840e | 2011-09-22 10:28:04 -0700 | [diff] [blame] | 1187 |   misc_info = common.LoadInfoDict(input_zip) | 
 | 1188 |  | 
 | 1189 |   BuildKeyMap(misc_info, key_mapping_options) | 
 | 1190 |  | 
| Tao Bao | aa7e993 | 2019-03-15 09:37:01 -0700 | [diff] [blame] | 1191 |   apk_keys_info, compressed_extension = common.ReadApkCerts(input_zip) | 
 | 1192 |   apk_keys = GetApkCerts(apk_keys_info) | 
| Doug Zongker | eb338ef | 2009-05-20 16:50:49 -0700 | [diff] [blame] | 1193 |  | 
| Tao Bao | aa7e993 | 2019-03-15 09:37:01 -0700 | [diff] [blame] | 1194 |   apex_keys_info = ReadApexKeysInfo(input_zip) | 
 | 1195 |   apex_keys = GetApexKeys(apex_keys_info, apk_keys) | 
 | 1196 |  | 
 | 1197 |   CheckApkAndApexKeysAvailable( | 
 | 1198 |       input_zip, | 
 | 1199 |       set(apk_keys.keys()) | set(apex_keys.keys()), | 
| Tao Bao | e134399 | 2019-03-19 12:24:03 -0700 | [diff] [blame] | 1200 |       compressed_extension, | 
 | 1201 |       apex_keys) | 
| Tao Bao | aa7e993 | 2019-03-15 09:37:01 -0700 | [diff] [blame] | 1202 |  | 
 | 1203 |   key_passwords = common.GetKeyPasswords( | 
 | 1204 |       set(apk_keys.values()) | set(itertools.chain(*apex_keys.values()))) | 
| Tao Bao | 9aa4b9b | 2016-09-29 17:53:56 -0700 | [diff] [blame] | 1205 |   platform_api_level, _ = GetApiLevelAndCodename(input_zip) | 
| Alex Klyubin | 2cfd1d1 | 2016-01-13 10:32:47 -0800 | [diff] [blame] | 1206 |   codename_to_api_level_map = GetCodenameToApiLevelMap(input_zip) | 
| Alex Klyubin | 2cfd1d1 | 2016-01-13 10:32:47 -0800 | [diff] [blame] | 1207 |  | 
| Doug Zongker | 412c02f | 2014-02-13 10:58:24 -0800 | [diff] [blame] | 1208 |   ProcessTargetFiles(input_zip, output_zip, misc_info, | 
| Tao Bao | aa7e993 | 2019-03-15 09:37:01 -0700 | [diff] [blame] | 1209 |                      apk_keys, apex_keys, key_passwords, | 
 | 1210 |                      platform_api_level, codename_to_api_level_map, | 
| Narayan Kamath | a07bf04 | 2017-08-14 14:49:21 +0100 | [diff] [blame] | 1211 |                      compressed_extension) | 
| Doug Zongker | 8e931bf | 2009-04-06 15:21:45 -0700 | [diff] [blame] | 1212 |  | 
| Tao Bao | 2ed665a | 2015-04-01 11:21:55 -0700 | [diff] [blame] | 1213 |   common.ZipClose(input_zip) | 
 | 1214 |   common.ZipClose(output_zip) | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 1215 |  | 
| Tianjie Xu | b48589a | 2016-08-03 19:21:52 -0700 | [diff] [blame] | 1216 |   # Skip building userdata.img and cache.img when signing the target files. | 
| Tianjie Xu | 616fbeb | 2017-05-23 14:51:02 -0700 | [diff] [blame] | 1217 |   new_args = ["--is_signing"] | 
 | 1218 |   # add_img_to_target_files builds the system image from scratch, so the | 
 | 1219 |   # recovery patch is guaranteed to be regenerated there. | 
 | 1220 |   if OPTIONS.rebuild_recovery: | 
 | 1221 |     new_args.append("--rebuild_recovery") | 
 | 1222 |   new_args.append(args[1]) | 
| Tianjie Xu | b48589a | 2016-08-03 19:21:52 -0700 | [diff] [blame] | 1223 |   add_img_to_target_files.main(new_args) | 
| Doug Zongker | 3c84f56 | 2014-07-31 11:06:30 -0700 | [diff] [blame] | 1224 |  | 
| Tao Bao | 0c28d2d | 2017-12-24 10:37:38 -0800 | [diff] [blame] | 1225 |   print("done.") | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 1226 |  | 
 | 1227 |  | 
 | 1228 | if __name__ == '__main__': | 
 | 1229 |   try: | 
 | 1230 |     main(sys.argv[1:]) | 
| Tao Bao | 0c28d2d | 2017-12-24 10:37:38 -0800 | [diff] [blame] | 1231 |   except common.ExternalError as e: | 
 | 1232 |     print("\n   ERROR: %s\n" % (e,)) | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 1233 |     sys.exit(1) | 
| Tao Bao | 639118f | 2017-06-19 15:48:02 -0700 | [diff] [blame] | 1234 |   finally: | 
 | 1235 |     common.Cleanup() |