Merge "Replace OTA keys when signing for A/B devices."
This commit is contained in:
@@ -51,10 +51,12 @@ Usage: sign_target_files_apks [flags] input_target_files output_target_files
|
|||||||
in which they appear on the command line.
|
in which they appear on the command line.
|
||||||
|
|
||||||
-o (--replace_ota_keys)
|
-o (--replace_ota_keys)
|
||||||
Replace the certificate (public key) used by OTA package
|
Replace the certificate (public key) used by OTA package verification
|
||||||
verification with the one specified in the input target_files
|
with the ones specified in the input target_files zip (in the
|
||||||
zip (in the META/otakeys.txt file). Key remapping (-k and -d)
|
META/otakeys.txt file). Key remapping (-k and -d) is performed on the
|
||||||
is performed on this key.
|
keys. For A/B devices, the payload verification key will be replaced
|
||||||
|
as well. If there're multiple OTA keys, only the first one will be used
|
||||||
|
for payload verification.
|
||||||
|
|
||||||
-t (--tag_changes) <+tag>,<-tag>,...
|
-t (--tag_changes) <+tag>,<-tag>,...
|
||||||
Comma-separated list of changes to make to the set of tags (in
|
Comma-separated list of changes to make to the set of tags (in
|
||||||
@@ -171,7 +173,9 @@ def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
|
|||||||
for i in input_tf_zip.infolist()
|
for i in input_tf_zip.infolist()
|
||||||
if i.filename.endswith('.apk')])
|
if i.filename.endswith('.apk')])
|
||||||
rebuild_recovery = False
|
rebuild_recovery = False
|
||||||
|
system_root_image = misc_info.get("system_root_image") == "true"
|
||||||
|
|
||||||
|
# tmpdir will only be used to regenerate the recovery-from-boot patch.
|
||||||
tmpdir = tempfile.mkdtemp()
|
tmpdir = tempfile.mkdtemp()
|
||||||
def write_to_temp(fn, attr, data):
|
def write_to_temp(fn, attr, data):
|
||||||
fn = os.path.join(tmpdir, fn)
|
fn = os.path.join(tmpdir, fn)
|
||||||
@@ -207,13 +211,6 @@ def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
|
|||||||
new_data = ReplaceVerityPublicKey(output_tf_zip, info.filename,
|
new_data = ReplaceVerityPublicKey(output_tf_zip, info.filename,
|
||||||
OPTIONS.replace_verity_public_key[1])
|
OPTIONS.replace_verity_public_key[1])
|
||||||
write_to_temp(info.filename, info.external_attr, new_data)
|
write_to_temp(info.filename, info.external_attr, new_data)
|
||||||
# Copy BOOT/, RECOVERY/, META/, ROOT/ to rebuild recovery patch.
|
|
||||||
elif (info.filename.startswith("BOOT/") or
|
|
||||||
info.filename.startswith("RECOVERY/") or
|
|
||||||
info.filename.startswith("META/") or
|
|
||||||
info.filename.startswith("ROOT/") or
|
|
||||||
info.filename == "SYSTEM/etc/recovery-resource.dat"):
|
|
||||||
write_to_temp(info.filename, info.external_attr, data)
|
|
||||||
|
|
||||||
# Sign APKs.
|
# Sign APKs.
|
||||||
if info.filename.endswith(".apk"):
|
if info.filename.endswith(".apk"):
|
||||||
@@ -228,6 +225,8 @@ def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
|
|||||||
# an APK we're not supposed to sign.
|
# an APK we're not supposed to sign.
|
||||||
print "NOT signing: %s" % (name,)
|
print "NOT signing: %s" % (name,)
|
||||||
common.ZipWriteStr(output_tf_zip, out_info, data)
|
common.ZipWriteStr(output_tf_zip, out_info, data)
|
||||||
|
|
||||||
|
# System properties.
|
||||||
elif info.filename in ("SYSTEM/build.prop",
|
elif info.filename in ("SYSTEM/build.prop",
|
||||||
"VENDOR/build.prop",
|
"VENDOR/build.prop",
|
||||||
"BOOT/RAMDISK/default.prop",
|
"BOOT/RAMDISK/default.prop",
|
||||||
@@ -238,19 +237,30 @@ def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
|
|||||||
if info.filename in ("BOOT/RAMDISK/default.prop",
|
if info.filename in ("BOOT/RAMDISK/default.prop",
|
||||||
"RECOVERY/RAMDISK/default.prop"):
|
"RECOVERY/RAMDISK/default.prop"):
|
||||||
write_to_temp(info.filename, info.external_attr, new_data)
|
write_to_temp(info.filename, info.external_attr, new_data)
|
||||||
|
|
||||||
elif info.filename.endswith("mac_permissions.xml"):
|
elif info.filename.endswith("mac_permissions.xml"):
|
||||||
print "rewriting %s with new keys." % (info.filename,)
|
print "rewriting %s with new keys." % (info.filename,)
|
||||||
new_data = ReplaceCerts(data)
|
new_data = ReplaceCerts(data)
|
||||||
common.ZipWriteStr(output_tf_zip, out_info, new_data)
|
common.ZipWriteStr(output_tf_zip, out_info, new_data)
|
||||||
|
|
||||||
|
# Trigger a rebuild of the recovery patch if needed.
|
||||||
elif info.filename in ("SYSTEM/recovery-from-boot.p",
|
elif info.filename in ("SYSTEM/recovery-from-boot.p",
|
||||||
"SYSTEM/etc/recovery.img",
|
"SYSTEM/etc/recovery.img",
|
||||||
"SYSTEM/bin/install-recovery.sh"):
|
"SYSTEM/bin/install-recovery.sh"):
|
||||||
rebuild_recovery = True
|
rebuild_recovery = True
|
||||||
|
|
||||||
|
# Don't copy OTA keys if we're replacing them.
|
||||||
elif (OPTIONS.replace_ota_keys and
|
elif (OPTIONS.replace_ota_keys and
|
||||||
info.filename in ("RECOVERY/RAMDISK/res/keys",
|
info.filename in (
|
||||||
"SYSTEM/etc/security/otacerts.zip")):
|
"BOOT/RAMDISK/res/keys",
|
||||||
# don't copy these files if we're regenerating them below
|
"RECOVERY/RAMDISK/res/keys",
|
||||||
|
"SYSTEM/etc/security/otacerts.zip",
|
||||||
|
"SYSTEM/etc/update_engine/update-payload-key.pub.pem")):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# Skip verity keys since they have been processed above.
|
||||||
|
# TODO: verity_key is at a wrong location (BOOT/verity_key). Will fix and
|
||||||
|
# clean up verity related lines in a separate CL.
|
||||||
elif (OPTIONS.replace_verity_private_key and
|
elif (OPTIONS.replace_verity_private_key and
|
||||||
info.filename == "META/misc_info.txt"):
|
info.filename == "META/misc_info.txt"):
|
||||||
pass
|
pass
|
||||||
@@ -258,14 +268,32 @@ def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
|
|||||||
info.filename in ("BOOT/RAMDISK/verity_key",
|
info.filename in ("BOOT/RAMDISK/verity_key",
|
||||||
"BOOT/verity_key")):
|
"BOOT/verity_key")):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# Copy BOOT/, RECOVERY/, META/, ROOT/ to rebuild recovery patch. This case
|
||||||
|
# must come AFTER other matching rules.
|
||||||
|
elif (info.filename.startswith("BOOT/") or
|
||||||
|
info.filename.startswith("RECOVERY/") or
|
||||||
|
info.filename.startswith("META/") or
|
||||||
|
info.filename.startswith("ROOT/") or
|
||||||
|
info.filename == "SYSTEM/etc/recovery-resource.dat"):
|
||||||
|
write_to_temp(info.filename, info.external_attr, data)
|
||||||
|
common.ZipWriteStr(output_tf_zip, out_info, data)
|
||||||
|
|
||||||
|
# A non-APK file; copy it verbatim.
|
||||||
else:
|
else:
|
||||||
# a non-APK file; copy it verbatim
|
|
||||||
common.ZipWriteStr(output_tf_zip, out_info, data)
|
common.ZipWriteStr(output_tf_zip, out_info, data)
|
||||||
|
|
||||||
if OPTIONS.replace_ota_keys:
|
if OPTIONS.replace_ota_keys:
|
||||||
new_recovery_keys = ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info)
|
new_recovery_keys = ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info)
|
||||||
if new_recovery_keys:
|
if new_recovery_keys:
|
||||||
write_to_temp("RECOVERY/RAMDISK/res/keys", 0o755 << 16, new_recovery_keys)
|
if system_root_image:
|
||||||
|
recovery_keys_location = "BOOT/RAMDISK/res/keys"
|
||||||
|
else:
|
||||||
|
recovery_keys_location = "RECOVERY/RAMDISK/res/keys"
|
||||||
|
# The "new_recovery_keys" has been already written into the output_tf_zip
|
||||||
|
# while calling ReplaceOtaKeys(). We're just putting the same copy to
|
||||||
|
# tmpdir in case we need to regenerate the recovery-from-boot patch.
|
||||||
|
write_to_temp(recovery_keys_location, 0o755 << 16, new_recovery_keys)
|
||||||
|
|
||||||
if rebuild_recovery:
|
if rebuild_recovery:
|
||||||
recovery_img = common.GetBootableImage(
|
recovery_img = common.GetBootableImage(
|
||||||
@@ -398,7 +426,8 @@ def ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info):
|
|||||||
"build/target/product/security/testkey")
|
"build/target/product/security/testkey")
|
||||||
mapped_keys.append(
|
mapped_keys.append(
|
||||||
OPTIONS.key_map.get(devkey, devkey) + ".x509.pem")
|
OPTIONS.key_map.get(devkey, devkey) + ".x509.pem")
|
||||||
print "META/otakeys.txt has no keys; using", mapped_keys[0]
|
print("META/otakeys.txt has no keys; using %s for OTA package"
|
||||||
|
" verification." % (mapped_keys[0],))
|
||||||
|
|
||||||
# recovery uses a version of the key that has been slightly
|
# recovery uses a version of the key that has been slightly
|
||||||
# predigested (by DumpPublicKey.java) and put in res/keys.
|
# predigested (by DumpPublicKey.java) and put in res/keys.
|
||||||
@@ -411,8 +440,13 @@ def ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info):
|
|||||||
new_recovery_keys, _ = p.communicate()
|
new_recovery_keys, _ = p.communicate()
|
||||||
if p.returncode != 0:
|
if p.returncode != 0:
|
||||||
raise common.ExternalError("failed to run dumpkeys")
|
raise common.ExternalError("failed to run dumpkeys")
|
||||||
common.ZipWriteStr(output_tf_zip, "RECOVERY/RAMDISK/res/keys",
|
|
||||||
new_recovery_keys)
|
# system_root_image puts the recovery keys at BOOT/RAMDISK.
|
||||||
|
if misc_info.get("system_root_image") == "true":
|
||||||
|
recovery_keys_location = "BOOT/RAMDISK/res/keys"
|
||||||
|
else:
|
||||||
|
recovery_keys_location = "RECOVERY/RAMDISK/res/keys"
|
||||||
|
common.ZipWriteStr(output_tf_zip, recovery_keys_location, new_recovery_keys)
|
||||||
|
|
||||||
# SystemUpdateActivity uses the x509.pem version of the keys, but
|
# SystemUpdateActivity uses the x509.pem version of the keys, but
|
||||||
# put into a zipfile system/etc/security/otacerts.zip.
|
# put into a zipfile system/etc/security/otacerts.zip.
|
||||||
@@ -426,6 +460,20 @@ def ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info):
|
|||||||
common.ZipWriteStr(output_tf_zip, "SYSTEM/etc/security/otacerts.zip",
|
common.ZipWriteStr(output_tf_zip, "SYSTEM/etc/security/otacerts.zip",
|
||||||
temp_file.getvalue())
|
temp_file.getvalue())
|
||||||
|
|
||||||
|
# For A/B devices, update the payload verification key.
|
||||||
|
if misc_info.get("ab_update") == "true":
|
||||||
|
# Unlike otacerts.zip that may contain multiple keys, we can only specify
|
||||||
|
# ONE payload verification key.
|
||||||
|
if len(mapped_keys) > 1:
|
||||||
|
print("\n WARNING: Found more than one OTA keys; Using the first one"
|
||||||
|
" as payload verification key.\n\n")
|
||||||
|
|
||||||
|
print "Using %s for payload verification." % (mapped_keys[0],)
|
||||||
|
common.ZipWrite(
|
||||||
|
output_tf_zip,
|
||||||
|
mapped_keys[0],
|
||||||
|
arcname="SYSTEM/etc/update_engine/update-payload-key.pub.pem")
|
||||||
|
|
||||||
return new_recovery_keys
|
return new_recovery_keys
|
||||||
|
|
||||||
def ReplaceVerityPublicKey(targetfile_zip, filename, key_path):
|
def ReplaceVerityPublicKey(targetfile_zip, filename, key_path):
|
||||||
|
Reference in New Issue
Block a user