aboutsummaryrefslogtreecommitdiff
path: root/tools/releasetools/sign_target_files_apks.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/releasetools/sign_target_files_apks.py')
-rwxr-xr-xtools/releasetools/sign_target_files_apks.py250
1 files changed, 151 insertions, 99 deletions
diff --git a/tools/releasetools/sign_target_files_apks.py b/tools/releasetools/sign_target_files_apks.py
index 47360c9464..2859948d1a 100755
--- a/tools/releasetools/sign_target_files_apks.py
+++ b/tools/releasetools/sign_target_files_apks.py
@@ -123,6 +123,17 @@ Usage: sign_target_files_apks [flags] input_target_files output_target_files
mounted on the partition (e.g. "--signing_helper /path/to/helper"). The
args will be appended to the existing ones in info dict.
+ --gki_signing_algorithm <algorithm>
+ --gki_signing_key <key>
+ Use the specified algorithm (e.g. SHA256_RSA4096) and the key to generate
+ 'boot signature' in a v4 boot.img. Otherwise it uses the existing values
+ in info dict.
+
+ --gki_signing_extra_args <args>
+ Specify any additional args that are needed to generate 'boot signature'
+ (e.g. --prop foo:bar). The args will be appended to the existing ones
+ in info dict.
+
--android_jar_path <path>
Path to the android.jar to repack the apex file.
"""
@@ -174,23 +185,50 @@ OPTIONS.tag_changes = ("-test-keys", "-dev-keys", "+release-keys")
OPTIONS.avb_keys = {}
OPTIONS.avb_algorithms = {}
OPTIONS.avb_extra_args = {}
+OPTIONS.gki_signing_key = None
+OPTIONS.gki_signing_algorithm = None
+OPTIONS.gki_signing_extra_args = None
OPTIONS.android_jar_path = None
AVB_FOOTER_ARGS_BY_PARTITION = {
- 'boot' : 'avb_boot_add_hash_footer_args',
- 'dtbo' : 'avb_dtbo_add_hash_footer_args',
- 'recovery' : 'avb_recovery_add_hash_footer_args',
- 'system' : 'avb_system_add_hashtree_footer_args',
- 'system_other' : 'avb_system_other_add_hashtree_footer_args',
- 'vendor' : 'avb_vendor_add_hashtree_footer_args',
- 'vendor_boot' : 'avb_vendor_boot_add_hash_footer_args',
- 'vbmeta' : 'avb_vbmeta_args',
- 'vbmeta_system' : 'avb_vbmeta_system_args',
- 'vbmeta_vendor' : 'avb_vbmeta_vendor_args',
+ 'boot': 'avb_boot_add_hash_footer_args',
+ 'dtbo': 'avb_dtbo_add_hash_footer_args',
+ 'product': 'avb_product_add_hashtree_footer_args',
+ 'recovery': 'avb_recovery_add_hash_footer_args',
+ 'system': 'avb_system_add_hashtree_footer_args',
+ 'system_ext': 'avb_system_ext_add_hashtree_footer_args',
+ 'system_other': 'avb_system_other_add_hashtree_footer_args',
+ 'odm': 'avb_odm_add_hashtree_footer_args',
+ 'odm_dlkm': 'avb_odm_dlkm_add_hashtree_footer_args',
+ 'pvmfw': 'avb_pvmfw_add_hash_footer_args',
+ 'vendor': 'avb_vendor_add_hashtree_footer_args',
+ 'vendor_boot': 'avb_vendor_boot_add_hash_footer_args',
+ 'vendor_dlkm': "avb_vendor_dlkm_add_hashtree_footer_args",
+ 'vbmeta': 'avb_vbmeta_args',
+ 'vbmeta_system': 'avb_vbmeta_system_args',
+ 'vbmeta_vendor': 'avb_vbmeta_vendor_args',
}
+# Check that AVB_FOOTER_ARGS_BY_PARTITION is in sync with AVB_PARTITIONS.
+for partition in common.AVB_PARTITIONS:
+ if partition not in AVB_FOOTER_ARGS_BY_PARTITION:
+ raise RuntimeError("Missing {} in AVB_FOOTER_ARGS".format(partition))
+
+
+def IsApexFile(filename):
+ return filename.endswith(".apex") or filename.endswith(".capex")
+
+
+def GetApexFilename(filename):
+ name = os.path.basename(filename)
+ # Replace the suffix for compressed apex
+ if name.endswith(".capex"):
+ return name.replace(".capex", ".apex")
+ return name
+
+
def GetApkCerts(certmap):
# apply the key remapping to the contents of the file
for apk, cert in certmap.items():
@@ -329,10 +367,9 @@ def CheckApkAndApexKeysAvailable(input_tf_zip, known_keys,
"""
unknown_files = []
for info in input_tf_zip.infolist():
- # Handle APEXes first, e.g. SYSTEM/apex/com.android.tzdata.apex.
- if (info.filename.startswith('SYSTEM/apex') and
- info.filename.endswith('.apex')):
- name = os.path.basename(info.filename)
+ # Handle APEXes on all partitions
+ if IsApexFile(info.filename):
+ name = GetApexFilename(info.filename)
if name not in known_keys:
unknown_files.append(name)
continue
@@ -363,11 +400,11 @@ def CheckApkAndApexKeysAvailable(input_tf_zip, known_keys,
invalid_apexes = []
for info in input_tf_zip.infolist():
- if (not info.filename.startswith('SYSTEM/apex') or
- not info.filename.endswith('.apex')):
+ if not IsApexFile(info.filename):
continue
- name = os.path.basename(info.filename)
+ name = GetApexFilename(info.filename)
+
(payload_key, container_key) = apex_keys[name]
if ((payload_key in common.SPECIAL_CERT_STRINGS and
container_key not in common.SPECIAL_CERT_STRINGS) or
@@ -383,8 +420,8 @@ def CheckApkAndApexKeysAvailable(input_tf_zip, known_keys,
def SignApk(data, keyname, pw, platform_api_level, codename_to_api_level_map,
- is_compressed):
- unsigned = tempfile.NamedTemporaryFile()
+ is_compressed, apk_name):
+ unsigned = tempfile.NamedTemporaryFile(suffix='_' + apk_name)
unsigned.write(data)
unsigned.flush()
@@ -402,7 +439,7 @@ def SignApk(data, keyname, pw, platform_api_level, codename_to_api_level_map,
unsigned.close()
unsigned = uncompressed
- signed = tempfile.NamedTemporaryFile()
+ signed = tempfile.NamedTemporaryFile(suffix='_' + apk_name)
# For pre-N builds, don't upgrade to SHA-256 JAR signatures based on the APK's
# minSdkVersion to avoid increasing incremental OTA update sizes. If an APK
@@ -445,6 +482,25 @@ def SignApk(data, keyname, pw, platform_api_level, codename_to_api_level_map,
return data
+def IsBuildPropFile(filename):
+ return filename in (
+ "SYSTEM/etc/prop.default",
+ "BOOT/RAMDISK/prop.default",
+ "RECOVERY/RAMDISK/prop.default",
+
+ "VENDOR_BOOT/RAMDISK/default.prop",
+ "VENDOR_BOOT/RAMDISK/prop.default",
+
+ # ROOT/default.prop is a legacy path, but may still exist for upgrading
+ # devices that don't support `property_overrides_split_enabled`.
+ "ROOT/default.prop",
+
+ # RECOVERY/RAMDISK/default.prop is a legacy path, but will always exist
+ # as a symlink in the current code. So it's a no-op here. Keeping the
+ # path here for clarity.
+ "RECOVERY/RAMDISK/default.prop") or filename.endswith("build.prop")
+
+
def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
apk_keys, apex_keys, key_passwords,
platform_api_level, codename_to_api_level_map,
@@ -488,7 +544,7 @@ def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
if key not in common.SPECIAL_CERT_STRINGS:
print(" signing: %-*s (%s)" % (maxsize, name, key))
signed_data = SignApk(data, key, key_passwords[key], platform_api_level,
- codename_to_api_level_map, is_compressed)
+ codename_to_api_level_map, is_compressed, name)
common.ZipWriteStr(output_tf_zip, out_info, signed_data)
else:
# an APK we're not supposed to sign.
@@ -497,9 +553,10 @@ def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
" (skipped due to special cert string)" % (name,))
common.ZipWriteStr(output_tf_zip, out_info, data)
- # Sign bundled APEX files.
- elif filename.startswith("SYSTEM/apex") and filename.endswith(".apex"):
- name = os.path.basename(filename)
+ # Sign bundled APEX files on all partitions
+ elif IsApexFile(filename):
+ name = GetApexFilename(filename)
+
payload_key, container_key = apex_keys[name]
# We've asserted not having a case with only one of them PRESIGNED.
@@ -515,7 +572,7 @@ def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
data,
payload_key,
container_key,
- key_passwords[container_key],
+ key_passwords,
apk_keys,
codename_to_api_level_map,
no_hashtree=True,
@@ -528,39 +585,8 @@ def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
" (skipped due to special cert string)" % (name,))
common.ZipWriteStr(output_tf_zip, out_info, data)
- # AVB public keys for the installed APEXes, which will be updated later.
- elif (os.path.dirname(filename) == 'SYSTEM/etc/security/apex' and
- filename != 'SYSTEM/etc/security/apex/'):
- continue
-
# System properties.
- elif filename in (
- "SYSTEM/build.prop",
-
- "VENDOR/build.prop",
- "SYSTEM/vendor/build.prop",
-
- "ODM/etc/build.prop",
- "VENDOR/odm/etc/build.prop",
-
- "PRODUCT/build.prop",
- "SYSTEM/product/build.prop",
-
- "SYSTEM_EXT/build.prop",
- "SYSTEM/system_ext/build.prop",
-
- "SYSTEM/etc/prop.default",
- "BOOT/RAMDISK/prop.default",
- "RECOVERY/RAMDISK/prop.default",
-
- # ROOT/default.prop is a legacy path, but may still exist for upgrading
- # devices that don't support `property_overrides_split_enabled`.
- "ROOT/default.prop",
-
- # RECOVERY/RAMDISK/default.prop is a legacy path, but will always exist
- # as a symlink in the current code. So it's a no-op here. Keeping the
- # path here for clarity.
- "RECOVERY/RAMDISK/default.prop"):
+ elif IsBuildPropFile(filename):
print("Rewriting %s:" % (filename,))
if stat.S_ISLNK(info.external_attr >> 16):
new_data = data
@@ -588,12 +614,7 @@ def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
# Don't copy OTA certs if we're replacing them.
# Replacement of update-payload-key.pub.pem was removed in b/116660991.
- elif (
- OPTIONS.replace_ota_keys and
- filename in (
- "BOOT/RAMDISK/system/etc/security/otacerts.zip",
- "RECOVERY/RAMDISK/system/etc/security/otacerts.zip",
- "SYSTEM/etc/security/otacerts.zip")):
+ elif OPTIONS.replace_ota_keys and filename.endswith("/otacerts.zip"):
pass
# Skip META/misc_info.txt since we will write back the new values later.
@@ -608,22 +629,30 @@ def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
elif (OPTIONS.remove_avb_public_keys and
(filename.startswith("BOOT/RAMDISK/avb/") or
filename.startswith("BOOT/RAMDISK/first_stage_ramdisk/avb/"))):
- matched_removal = False
- for key_to_remove in OPTIONS.remove_avb_public_keys:
- if filename.endswith(key_to_remove):
- matched_removal = True
- print("Removing AVB public key from ramdisk: %s" % filename)
- break
- if not matched_removal:
- # Copy it verbatim if we don't want to remove it.
- common.ZipWriteStr(output_tf_zip, out_info, data)
+ matched_removal = False
+ for key_to_remove in OPTIONS.remove_avb_public_keys:
+ if filename.endswith(key_to_remove):
+ matched_removal = True
+ print("Removing AVB public key from ramdisk: %s" % filename)
+ break
+ if not matched_removal:
+ # Copy it verbatim if we don't want to remove it.
+ common.ZipWriteStr(output_tf_zip, out_info, data)
# Skip verity keyid (for system_root_image use) if we will replace it.
elif OPTIONS.replace_verity_keyid and filename == "BOOT/cmdline":
pass
+ # Skip the vbmeta digest as we will recalculate it.
+ elif filename == "META/vbmeta_digest.txt":
+ pass
+
# Skip the care_map as we will regenerate the system/vendor images.
- elif filename == "META/care_map.pb" or filename == "META/care_map.txt":
+ elif filename in ["META/care_map.pb", "META/care_map.txt"]:
+ pass
+
+ # Skip apex_info.pb because we sign/modify apexes
+ elif filename == "META/apex_info.pb":
pass
# Updates system_other.avbpubkey in /product/etc/.
@@ -680,6 +709,9 @@ def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
if misc_info.get('avb_enable') == 'true':
RewriteAvbProps(misc_info)
+ # Replace the GKI signing key for boot.img, if any.
+ ReplaceGkiSigningKey(misc_info)
+
# Write back misc_info with the latest values.
ReplaceMiscInfoTxt(input_tf_zip, output_tf_zip, misc_info)
@@ -785,7 +817,7 @@ def RewriteProps(data):
value = "/".join(pieces)
elif key == "ro.build.description":
pieces = value.split(" ")
- assert len(pieces) == 5
+ assert pieces[-1].endswith("-keys")
pieces[-1] = EditTags(pieces[-1])
value = " ".join(pieces)
elif key.startswith("ro.") and key.endswith(".build.tags"):
@@ -813,7 +845,7 @@ def WriteOtacerts(output_zip, filename, keys):
keys: A list of public keys to use during OTA package verification.
"""
temp_file = io.BytesIO()
- certs_zip = zipfile.ZipFile(temp_file, "w")
+ certs_zip = zipfile.ZipFile(temp_file, "w", allowZip64=True)
for k in keys:
common.ZipWrite(certs_zip, k)
common.ZipClose(certs_zip)
@@ -857,21 +889,12 @@ def ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info):
print("META/otakeys.txt has no keys; using %s for OTA package"
" verification." % (mapped_keys[0],))
- # recovery now uses the same x509.pem version of the keys.
- # extra_recovery_keys are used only in recovery.
- if misc_info.get("recovery_as_boot") == "true":
- recovery_keys_location = "BOOT/RAMDISK/system/etc/security/otacerts.zip"
- else:
- recovery_keys_location = "RECOVERY/RAMDISK/system/etc/security/otacerts.zip"
-
- WriteOtacerts(output_tf_zip, recovery_keys_location,
- mapped_keys + extra_recovery_keys)
-
- # SystemUpdateActivity uses the x509.pem version of the keys, but
- # put into a zipfile system/etc/security/otacerts.zip.
- # We DO NOT include the extra_recovery_keys (if any) here.
- WriteOtacerts(output_tf_zip, "SYSTEM/etc/security/otacerts.zip", mapped_keys)
-
+ otacerts = [info
+ for info in input_tf_zip.infolist()
+ if info.filename.endswith("/otacerts.zip")]
+ for info in otacerts:
+ print("Rewriting OTA key:", info.filename, mapped_keys)
+ WriteOtacerts(output_tf_zip, info.filename, mapped_keys)
def ReplaceVerityPublicKey(output_zip, filename, key_path):
@@ -967,11 +990,10 @@ def ReplaceAvbSigningKeys(misc_info):
if extra_args:
print('Setting extra AVB signing args for %s to "%s"' % (
partition, extra_args))
- if partition in AVB_FOOTER_ARGS_BY_PARTITION:
- args_key = AVB_FOOTER_ARGS_BY_PARTITION[partition]
- else:
- # custom partition
- args_key = "avb_{}_add_hashtree_footer_args".format(partition)
+ args_key = AVB_FOOTER_ARGS_BY_PARTITION.get(
+ partition,
+ # custom partition
+ "avb_{}_add_hashtree_footer_args".format(partition))
misc_info[args_key] = (misc_info.get(args_key, '') + ' ' + extra_args)
for partition in AVB_FOOTER_ARGS_BY_PARTITION:
@@ -1008,6 +1030,27 @@ def RewriteAvbProps(misc_info):
misc_info[args_key] = result
+def ReplaceGkiSigningKey(misc_info):
+ """Replaces the GKI signing key."""
+
+ key = OPTIONS.gki_signing_key
+ if not key:
+ return
+
+ algorithm = OPTIONS.gki_signing_algorithm
+ if not algorithm:
+ raise ValueError("Missing --gki_signing_algorithm")
+
+ print('Replacing GKI signing key with "%s" (%s)' % (key, algorithm))
+ misc_info["gki_signing_algorithm"] = algorithm
+ misc_info["gki_signing_key_path"] = key
+
+ extra_args = OPTIONS.gki_signing_extra_args
+ if extra_args:
+ print('Setting GKI signing args: "%s"' % (extra_args))
+ misc_info["gki_signing_signature_args"] = extra_args
+
+
def BuildKeyMap(misc_info, key_mapping_options):
for s, d in key_mapping_options:
if s is None: # -d option
@@ -1117,7 +1160,7 @@ def ReadApexKeysInfo(tf_zip):
privkey.endswith(privkey_suffix) and
pubkey[:-pubkey_suffix_len] == privkey[:-privkey_suffix_len])
- # Sanity check on the container key names, as we'll carry them without the
+ # Check the container key names, as we'll carry them without the
# extensions. This doesn't apply to payload keys though, which we will use
# full names only.
container_cert = matches.group("CONTAINER_CERT")
@@ -1150,7 +1193,7 @@ def main(argv):
apex_name, key = a.split("=")
OPTIONS.extra_apex_payload_keys[apex_name] = key
elif o == "--skip_apks_with_path_prefix":
- # Sanity check the prefix, which must be in all upper case.
+ # Check the prefix, which must be in all upper case.
prefix = a.split('/')[0]
if not prefix or prefix != prefix.upper():
raise ValueError("Invalid path prefix '%s'" % (a,))
@@ -1239,6 +1282,12 @@ def main(argv):
# 'oem=--signing_helper_with_files=/tmp/avbsigner.sh'.
partition, extra_args = a.split("=", 1)
OPTIONS.avb_extra_args[partition] = extra_args
+ elif o == "--gki_signing_key":
+ OPTIONS.gki_signing_key = a
+ elif o == "--gki_signing_algorithm":
+ OPTIONS.gki_signing_algorithm = a
+ elif o == "--gki_signing_extra_args":
+ OPTIONS.gki_signing_extra_args = a
else:
return False
return True
@@ -1286,6 +1335,9 @@ def main(argv):
"avb_extra_custom_image_key=",
"avb_extra_custom_image_algorithm=",
"avb_extra_custom_image_extra_args=",
+ "gki_signing_key=",
+ "gki_signing_algorithm=",
+ "gki_signing_extra_args=",
],
extra_option_handler=option_handler)
@@ -1295,7 +1347,7 @@ def main(argv):
common.InitLogging()
- input_zip = zipfile.ZipFile(args[0], "r")
+ input_zip = zipfile.ZipFile(args[0], "r", allowZip64=True)
output_zip = zipfile.ZipFile(args[1], "w",
compression=zipfile.ZIP_DEFLATED,
allowZip64=True)
@@ -1348,6 +1400,6 @@ if __name__ == '__main__':
main(sys.argv[1:])
except common.ExternalError as e:
print("\n ERROR: %s\n" % (e,))
- sys.exit(1)
+ raise
finally:
common.Cleanup()