def main(argv): options = {} def option_handler(o, a): if o == '--container_key': # Strip the suffix if any, as common.SignFile expects no suffix. DEFAULT_CONTAINER_KEY_SUFFIX = '.x509.pem' if a.endswith(DEFAULT_CONTAINER_KEY_SUFFIX): a = a[:-len(DEFAULT_CONTAINER_KEY_SUFFIX)] options['container_key'] = a elif o == '--payload_key': options['payload_key'] = a elif o == '--payload_extra_args': options['payload_extra_args'] = a else: return False return True args = common.ParseOptions(argv, __doc__, extra_opts='', extra_long_opts=[ 'container_key=', 'payload_extra_args=', 'payload_key=', ], extra_option_handler=option_handler) if (len(args) != 2 or 'container_key' not in options or 'payload_key' not in options): common.Usage(__doc__) sys.exit(1) common.InitLogging() input_zip = args[0] output_zip = args[1] with open(input_zip) as input_fp: apex_data = input_fp.read() signed_apex = apex_utils.SignApex( apex_data, payload_key=options['payload_key'], container_key=options['container_key'], container_pw=None, codename_to_api_level_map=None, signing_args=options.get('payload_extra_args')) shutil.copyfile(signed_apex, output_zip) logger.info("done.")
def SignApexFile(avbtool, apex_file, payload_key, container_key, no_hashtree, apk_keys=None, signing_args=None, codename_to_api_level_map=None, sign_tool=None): """Signs the given apex file.""" with open(apex_file, 'rb') as input_fp: apex_data = input_fp.read() return apex_utils.SignApex( avbtool, apex_data, payload_key=payload_key, container_key=container_key, container_pw=None, codename_to_api_level_map=codename_to_api_level_map, no_hashtree=no_hashtree, apk_keys=apk_keys, signing_args=signing_args, sign_tool=sign_tool)
def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info, apk_keys, apex_keys, key_passwords, platform_api_level, codename_to_api_level_map, compressed_extension): # maxsize measures the maximum filename length, including the ones to be # skipped. maxsize = max( [len(os.path.basename(i.filename)) for i in input_tf_zip.infolist() if GetApkFileInfo(i.filename, compressed_extension, [])[0]]) system_root_image = misc_info.get("system_root_image") == "true" for info in input_tf_zip.infolist(): filename = info.filename if filename.startswith("IMAGES/"): continue # Skip split super images, which will be re-generated during signing. if filename.startswith("OTA/") and filename.endswith(".img"): continue data = input_tf_zip.read(filename) out_info = copy.copy(info) (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo( filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix) if is_apk and should_be_skipped: # Copy skipped APKs verbatim. print( "NOT signing: %s\n" " (skipped due to matching prefix)" % (filename,)) common.ZipWriteStr(output_tf_zip, out_info, data) # Sign APKs. elif is_apk: name = os.path.basename(filename) if is_compressed: name = name[:-len(compressed_extension)] key = apk_keys[name] 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) common.ZipWriteStr(output_tf_zip, out_info, signed_data) else: # an APK we're not supposed to sign. print( "NOT signing: %s\n" " (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) payload_key, container_key = apex_keys[name] # We've asserted not having a case with only one of them PRESIGNED. if (payload_key not in common.SPECIAL_CERT_STRINGS and container_key not in common.SPECIAL_CERT_STRINGS): print(" signing: %-*s container (%s)" % ( maxsize, name, container_key)) print(" : %-*s payload (%s)" % ( maxsize, name, payload_key)) signed_apex = apex_utils.SignApex( data, payload_key, container_key, key_passwords[container_key], codename_to_api_level_map, OPTIONS.avb_extra_args.get('apex')) common.ZipWrite(output_tf_zip, signed_apex, filename) else: print( "NOT signing: %s\n" " (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/build.prop", # legacy "ODM/etc/build.prop", "VENDOR/odm/build.prop", # legacy "VENDOR/odm/etc/build.prop", "PRODUCT/build.prop", "SYSTEM/product/build.prop", "PRODUCT_SERVICES/build.prop", "SYSTEM/product_services/build.prop", "SYSTEM/etc/prop.default", "BOOT/RAMDISK/prop.default", "BOOT/RAMDISK/default.prop", # legacy "ROOT/default.prop", # legacy "RECOVERY/RAMDISK/prop.default", "RECOVERY/RAMDISK/default.prop"): # legacy print("Rewriting %s:" % (filename,)) if stat.S_ISLNK(info.external_attr >> 16): new_data = data else: new_data = RewriteProps(data) common.ZipWriteStr(output_tf_zip, out_info, new_data) # Replace the certs in *mac_permissions.xml (there could be multiple, such # as {system,vendor}/etc/selinux/{plat,nonplat}_mac_permissions.xml). elif filename.endswith("mac_permissions.xml"): print("Rewriting %s with new keys." % (filename,)) new_data = ReplaceCerts(data) common.ZipWriteStr(output_tf_zip, out_info, new_data) # Ask add_img_to_target_files to rebuild the recovery patch if needed. elif filename in ("SYSTEM/recovery-from-boot.p", "SYSTEM/etc/recovery.img", "SYSTEM/bin/install-recovery.sh"): OPTIONS.rebuild_recovery = True # Don't copy OTA certs if we're replacing them. elif ( OPTIONS.replace_ota_keys and filename in ( "BOOT/RAMDISK/system/etc/security/otacerts.zip", "BOOT/RAMDISK/system/etc/update_engine/update-payload-key.pub.pem", "RECOVERY/RAMDISK/system/etc/security/otacerts.zip", "SYSTEM/etc/security/otacerts.zip", "SYSTEM/etc/update_engine/update-payload-key.pub.pem")): pass # Skip META/misc_info.txt since we will write back the new values later. elif filename == "META/misc_info.txt": pass # Skip verity public key if we will replace it. elif (OPTIONS.replace_verity_public_key and filename in ("BOOT/RAMDISK/verity_key", "ROOT/verity_key")): pass # 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 care_map as we will regenerate the system/vendor images. elif filename == "META/care_map.pb" or filename == "META/care_map.txt": pass # Updates system_other.avbpubkey in /product/etc/. elif filename in ( "PRODUCT/etc/security/avb/system_other.avbpubkey", "SYSTEM/product/etc/security/avb/system_other.avbpubkey"): # Only update system_other's public key, if the corresponding signing # key is specified via --avb_system_other_key. signing_key = OPTIONS.avb_keys.get("system_other") if signing_key: public_key = common.ExtractAvbPublicKey(signing_key) print(" Rewriting AVB public key of system_other in /product") common.ZipWrite(output_tf_zip, public_key, filename) # Should NOT sign boot-debug.img. elif filename in ( "BOOT/RAMDISK/force_debuggable", "RECOVERY/RAMDISK/force_debuggable" "RECOVERY/RAMDISK/first_stage_ramdisk/force_debuggable"): raise common.ExternalError("debuggable boot.img cannot be signed") # A non-APK file; copy it verbatim. else: common.ZipWriteStr(output_tf_zip, out_info, data) if OPTIONS.replace_ota_keys: ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info) # Replace the keyid string in misc_info dict. if OPTIONS.replace_verity_private_key: ReplaceVerityPrivateKey(misc_info, OPTIONS.replace_verity_private_key[1]) if OPTIONS.replace_verity_public_key: dest = "ROOT/verity_key" if system_root_image else "BOOT/RAMDISK/verity_key" # We are replacing the one in boot image only, since the one under # recovery won't ever be needed. ReplaceVerityPublicKey( output_tf_zip, dest, OPTIONS.replace_verity_public_key[1]) # Replace the keyid string in BOOT/cmdline. if OPTIONS.replace_verity_keyid: ReplaceVerityKeyId(input_tf_zip, output_tf_zip, OPTIONS.replace_verity_keyid[1]) # Replace the AVB signing keys, if any. ReplaceAvbSigningKeys(misc_info) # Write back misc_info with the latest values. ReplaceMiscInfoTxt(input_tf_zip, output_tf_zip, misc_info)
def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info, apk_keys, apex_keys, key_passwords, platform_api_level, codename_to_api_level_map, compressed_extension): # maxsize measures the maximum filename length, including the ones to be # skipped. maxsize = max( [len(os.path.basename(i.filename)) for i in input_tf_zip.infolist() if GetApkFileInfo(i.filename, compressed_extension, [])[0]]) system_root_image = misc_info.get("system_root_image") == "true" for info in input_tf_zip.infolist(): filename = info.filename if filename.startswith("IMAGES/"): continue # Skip OTA-specific images (e.g. split super images), which will be # re-generated during signing. if filename.startswith("OTA/") and filename.endswith(".img"): continue data = input_tf_zip.read(filename) out_info = copy.copy(info) (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo( filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix) if is_apk and should_be_skipped: # Copy skipped APKs verbatim. print( "NOT signing: %s\n" " (skipped due to matching prefix)" % (filename,)) common.ZipWriteStr(output_tf_zip, out_info, data) # Sign APKs. elif is_apk: name = os.path.basename(filename) if is_compressed: name = name[:-len(compressed_extension)] key = apk_keys[name] 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) common.ZipWriteStr(output_tf_zip, out_info, signed_data) else: # an APK we're not supposed to sign. print( "NOT signing: %s\n" " (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) payload_key, container_key = apex_keys[name] # We've asserted not having a case with only one of them PRESIGNED. if (payload_key not in common.SPECIAL_CERT_STRINGS and container_key not in common.SPECIAL_CERT_STRINGS): print(" signing: %-*s container (%s)" % ( maxsize, name, container_key)) print(" : %-*s payload (%s)" % ( maxsize, name, payload_key)) avbtool = misc_info['avb_avbtool'] if 'avb_avbtool' in misc_info else 'avbtool' signed_apex = apex_utils.SignApex( avbtool, data, payload_key, container_key, key_passwords[container_key], apk_keys, codename_to_api_level_map, no_hashtree=True, signing_args=OPTIONS.avb_extra_args.get('apex')) common.ZipWrite(output_tf_zip, signed_apex, filename) else: print( "NOT signing: %s\n" " (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"): print("Rewriting %s:" % (filename,)) if stat.S_ISLNK(info.external_attr >> 16): new_data = data else: new_data = RewriteProps(data.decode()) common.ZipWriteStr(output_tf_zip, out_info, new_data) # Replace the certs in *mac_permissions.xml (there could be multiple, such # as {system,vendor}/etc/selinux/{plat,nonplat}_mac_permissions.xml). elif filename.endswith("mac_permissions.xml"): print("Rewriting %s with new keys." % (filename,)) new_data = ReplaceCerts(data.decode()) common.ZipWriteStr(output_tf_zip, out_info, new_data) elif info.filename.startswith("SYSTEM/etc/permissions/"): print("rewriting %s with new keys." % info.filename) new_data = ReplaceCerts(data) common.ZipWriteStr(output_tf_zip, out_info, new_data) # Ask add_img_to_target_files to rebuild the recovery patch if needed. elif filename in ("SYSTEM/recovery-from-boot.p", "VENDOR/recovery-from-boot.p", "SYSTEM/etc/recovery.img", "VENDOR/etc/recovery.img", "SYSTEM/bin/install-recovery.sh", "VENDOR/bin/install-recovery.sh"): OPTIONS.rebuild_recovery = True # 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")): pass # Skip META/misc_info.txt since we will write back the new values later. elif filename == "META/misc_info.txt": pass # Skip verity public key if we will replace it. elif (OPTIONS.replace_verity_public_key and filename in ("BOOT/RAMDISK/verity_key", "ROOT/verity_key")): pass 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) # 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 care_map as we will regenerate the system/vendor images. elif filename == "META/care_map.pb" or filename == "META/care_map.txt": pass # Updates system_other.avbpubkey in /product/etc/. elif filename in ( "PRODUCT/etc/security/avb/system_other.avbpubkey", "SYSTEM/product/etc/security/avb/system_other.avbpubkey"): # Only update system_other's public key, if the corresponding signing # key is specified via --avb_system_other_key. signing_key = OPTIONS.avb_keys.get("system_other") if signing_key: avbtool = misc_info['avb_avbtool'] if 'avb_avbtool' in misc_info else 'avbtool' public_key = common.ExtractAvbPublicKey( avbtool, signing_key) print(" Rewriting AVB public key of system_other in /product") common.ZipWrite(output_tf_zip, public_key, filename) # Should NOT sign boot-debug.img. elif filename in ( "BOOT/RAMDISK/force_debuggable", "BOOT/RAMDISK/first_stage_ramdisk/force_debuggable"): raise common.ExternalError("debuggable boot.img cannot be signed") # A non-APK file; copy it verbatim. else: common.ZipWriteStr(output_tf_zip, out_info, data) if OPTIONS.replace_ota_keys: ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info) # Replace the keyid string in misc_info dict. if OPTIONS.replace_verity_private_key: ReplaceVerityPrivateKey(misc_info, OPTIONS.replace_verity_private_key[1]) if OPTIONS.replace_verity_public_key: # Replace the one in root dir in system.img. ReplaceVerityPublicKey( output_tf_zip, 'ROOT/verity_key', OPTIONS.replace_verity_public_key[1]) if not system_root_image: # Additionally replace the copy in ramdisk if not using system-as-root. ReplaceVerityPublicKey( output_tf_zip, 'BOOT/RAMDISK/verity_key', OPTIONS.replace_verity_public_key[1]) # Replace the keyid string in BOOT/cmdline. if OPTIONS.replace_verity_keyid: ReplaceVerityKeyId(input_tf_zip, output_tf_zip, OPTIONS.replace_verity_keyid[1]) # Replace the AVB signing keys, if any. ReplaceAvbSigningKeys(misc_info) # Rewrite the props in AVB signing args. if misc_info.get('avb_enable') == 'true': RewriteAvbProps(misc_info) # Write back misc_info with the latest values. ReplaceMiscInfoTxt(input_tf_zip, output_tf_zip, misc_info)