def SignApk(data, keyname, pw, platform_api_level, codename_to_api_level_map): unsigned = tempfile.NamedTemporaryFile() unsigned.write(data) unsigned.flush() signed = tempfile.NamedTemporaryFile() # 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 # didn't change, we don't want its signature to change due to the switch # from SHA-1 to SHA-256. # By default, APK signer chooses SHA-256 signatures if the APK's minSdkVersion # is 18 or higher. For pre-N builds we disable this mechanism by pretending # that the APK's minSdkVersion is 1. # For N+ builds, we let APK signer rely on the APK's minSdkVersion to # determine whether to use SHA-256. min_api_level = None if platform_api_level > 23: # Let APK signer choose whether to use SHA-1 or SHA-256, based on the APK's # minSdkVersion attribute min_api_level = None else: # Force APK signer to use SHA-1 min_api_level = 1 common.SignFile(unsigned.name, signed.name, keyname, pw, min_api_level=min_api_level, codename_to_api_level_map=codename_to_api_level_map) data = signed.read() unsigned.close() signed.close() return data
def ExtractApexPayloadAndSignApks(self, apk_entries, apk_keys): """Extracts the payload image and signs the containing apk files.""" if not os.path.exists(self.debugfs_path): raise ApexSigningError( "Couldn't find location of debugfs_static: " + "Path {} does not exist. ".format(self.debugfs_path) + "Make sure bin/debugfs_static can be found in -p <path>") payload_dir = common.MakeTempDir() extract_cmd = ['deapexer', '--debugfs_path', self.debugfs_path, 'extract', self.apex_path, payload_dir] common.RunAndCheckOutput(extract_cmd) has_signed_apk = False for entry in apk_entries: apk_path = os.path.join(payload_dir, entry) assert os.path.exists(self.apex_path) key_name = apk_keys.get(os.path.basename(entry)) if key_name in common.SPECIAL_CERT_STRINGS: logger.info('Not signing: %s due to special cert string', apk_path) continue logger.info('Signing apk file %s in apex %s', apk_path, self.apex_path) # Rename the unsigned apk and overwrite the original apk path with the # signed apk file. unsigned_apk = common.MakeTempFile() os.rename(apk_path, unsigned_apk) common.SignFile( unsigned_apk, apk_path, key_name, self.key_passwords.get(key_name), codename_to_api_level_map=self.codename_to_api_level_map) has_signed_apk = True return payload_dir, has_signed_apk
def ExtractApexPayloadAndSignApks(self, apk_entries, apk_keys): """Extracts the payload image and signs the containing apk files.""" payload_dir = common.MakeTempDir() extract_cmd = ['deapexer', 'extract', self.apex_path, payload_dir] common.RunAndCheckOutput(extract_cmd) has_signed_apk = False for entry in apk_entries: apk_path = os.path.join(payload_dir, entry) assert os.path.exists(self.apex_path) key_name = apk_keys.get(os.path.basename(entry)) if key_name in common.SPECIAL_CERT_STRINGS: logger.info('Not signing: %s due to special cert string', apk_path) continue logger.info('Signing apk file %s in apex %s', apk_path, self.apex_path) # Rename the unsigned apk and overwrite the original apk path with the # signed apk file. unsigned_apk = common.MakeTempFile() os.rename(apk_path, unsigned_apk) common.SignFile( unsigned_apk, apk_path, key_name, self.key_passwords, codename_to_api_level_map=self.codename_to_api_level_map) has_signed_apk = True return payload_dir, has_signed_apk
def SignApk(data, keyname, pw, platform_api_level, codename_to_api_level_map, is_compressed): unsigned = tempfile.NamedTemporaryFile() unsigned.write(data) unsigned.flush() if is_compressed: uncompressed = tempfile.NamedTemporaryFile() with gzip.open(unsigned.name, "rb") as in_file, open(uncompressed.name, "wb") as out_file: shutil.copyfileobj(in_file, out_file) # Finally, close the "unsigned" file (which is gzip compressed), and then # replace it with the uncompressed version. # # TODO(narayan): All this nastiness can be avoided if python 3.2 is in use, # we could just gzip / gunzip in-memory buffers instead. unsigned.close() unsigned = uncompressed signed = tempfile.NamedTemporaryFile() # 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 # didn't change, we don't want its signature to change due to the switch # from SHA-1 to SHA-256. # By default, APK signer chooses SHA-256 signatures if the APK's minSdkVersion # is 18 or higher. For pre-N builds we disable this mechanism by pretending # that the APK's minSdkVersion is 1. # For N+ builds, we let APK signer rely on the APK's minSdkVersion to # determine whether to use SHA-256. min_api_level = None if platform_api_level > 23: # Let APK signer choose whether to use SHA-1 or SHA-256, based on the APK's # minSdkVersion attribute min_api_level = None else: # Force APK signer to use SHA-1 min_api_level = 1 common.SignFile(unsigned.name, signed.name, keyname, pw, min_api_level=min_api_level, codename_to_api_level_map=codename_to_api_level_map) data = None; if is_compressed: # Recompress the file after it has been signed. compressed = tempfile.NamedTemporaryFile() with open(signed.name, "rb") as in_file, gzip.open(compressed.name, "wb") as out_file: shutil.copyfileobj(in_file, out_file) data = compressed.read() compressed.close() else: data = signed.read() unsigned.close() signed.close() return data
def SignApex(apex_data, payload_key, container_key, container_pw, codename_to_api_level_map, signing_args=None): """Signs the current APEX with the given payload/container keys. Args: apex_data: Raw APEX data. payload_key: The path to payload signing key (w/o extension). container_key: The path to container signing key (w/o extension). container_pw: The matching password of the container_key, or None. codename_to_api_level_map: A dict that maps from codename to API level. signing_args: Additional args to be passed to the payload signer. Returns: (signed_apex, payload_key_name): signed_apex is the path to the signed APEX file; payload_key_name is a str of the payload signing key name (e.g. com.android.tzdata). """ apex_file = common.MakeTempFile(prefix='apex-', suffix='.apex') with open(apex_file, 'wb') as apex_fp: apex_fp.write(apex_data) APEX_PAYLOAD_IMAGE = 'apex_payload.img' # Signing an APEX is a two step process. # 1. Extract and sign the APEX_PAYLOAD_IMAGE entry with the given payload_key. payload_dir = common.MakeTempDir(prefix='apex-payload-') with zipfile.ZipFile(apex_file) as apex_fd: payload_file = apex_fd.extract(APEX_PAYLOAD_IMAGE, payload_dir) payload_info = apex_utils.ParseApexPayloadInfo(payload_file) apex_utils.SignApexPayload(payload_file, payload_key, payload_info['apex.key'], payload_info['Algorithm'], payload_info['Salt'], signing_args) common.ZipDelete(apex_file, APEX_PAYLOAD_IMAGE) apex_zip = zipfile.ZipFile(apex_file, 'a') common.ZipWrite(apex_zip, payload_file, arcname=APEX_PAYLOAD_IMAGE) common.ZipClose(apex_zip) # 2. Sign the overall APEX container with container_key. signed_apex = common.MakeTempFile(prefix='apex-container-', suffix='.apex') common.SignFile(apex_file, signed_apex, container_key, container_pw, codename_to_api_level_map=codename_to_api_level_map) signed_and_aligned_apex = common.MakeTempFile(prefix='apex-container-', suffix='.apex') common.RunAndCheckOutput( ['zipalign', '-f', '4096', signed_apex, signed_and_aligned_apex]) return (signed_and_aligned_apex, payload_info['apex.key'])
def SignOutput(input_zip_name, output_zip_name): key_passwords = common.GetKeyPasswords([OPTIONS.package_key]) pw = key_passwords[OPTIONS.package_key] common.SignFile(input_zip_name, output_zip_name, OPTIONS.package_key, pw, whole_file=True)
def SignApk(data, keyname, pw): unsigned = tempfile.NamedTemporaryFile() unsigned.write(data) unsigned.flush() signed = tempfile.NamedTemporaryFile() common.SignFile(unsigned.name, signed.name, keyname, pw, align=4) data = signed.read() unsigned.close() signed.close() return data
def SignCompressedApex(avbtool, apex_file, payload_key, container_key, container_pw, apk_keys, codename_to_api_level_map, no_hashtree, signing_args=None): """Signs the current compressed APEX with the given payload/container keys. Args: apex_file: Raw uncompressed APEX data. payload_key: The path to payload signing key (w/ extension). container_key: The path to container signing key (w/o extension). container_pw: The matching password of the container_key, or None. apk_keys: A dict that holds the signing keys for apk files. codename_to_api_level_map: A dict that maps from codename to API level. no_hashtree: Don't include hashtree in the signed APEX. signing_args: Additional args to be passed to the payload signer. Returns: The path to the signed APEX file. """ debugfs_path = os.path.join(OPTIONS.search_path, 'bin', 'debugfs_static') # 1. Decompress original_apex inside compressed apex. original_apex_file = common.MakeTempFile(prefix='original-apex-', suffix='.apex') # Decompression target path should not exist os.remove(original_apex_file) common.RunAndCheckOutput(['deapexer', '--debugfs_path', debugfs_path, 'decompress', '--input', apex_file, '--output', original_apex_file]) # 2. Sign original_apex signed_original_apex_file = SignUncompressedApex( avbtool, original_apex_file, payload_key, container_key, container_pw, apk_keys, codename_to_api_level_map, no_hashtree, signing_args) # 3. Compress signed original apex. compressed_apex_file = common.MakeTempFile(prefix='apex-container-', suffix='.capex') common.RunAndCheckOutput(['apex_compression_tool', 'compress', '--apex_compression_tool_path', os.getenv('PATH'), '--input', signed_original_apex_file, '--output', compressed_apex_file]) # 4. Sign the APEX container with container_key. signed_apex = common.MakeTempFile(prefix='apex-container-', suffix='.capex') password = container_pw.get(container_key) if container_pw else None common.SignFile( compressed_apex_file, signed_apex, container_key, password, codename_to_api_level_map=codename_to_api_level_map, extra_signapk_args=OPTIONS.extra_signapk_args) return signed_apex
def SignUncompressedApex(avbtool, apex_file, payload_key, container_key, container_pw, apk_keys, codename_to_api_level_map, no_hashtree, signing_args=None): """Signs the current uncompressed APEX with the given payload/container keys. Args: apex_file: Uncompressed APEX file. payload_key: The path to payload signing key (w/ extension). container_key: The path to container signing key (w/o extension). container_pw: The matching password of the container_key, or None. apk_keys: A dict that holds the signing keys for apk files. codename_to_api_level_map: A dict that maps from codename to API level. no_hashtree: Don't include hashtree in the signed APEX. signing_args: Additional args to be passed to the payload signer. Returns: The path to the signed APEX file. """ # 1. Extract the apex payload image and sign the containing apk files. Repack # the apex file after signing. apk_signer = ApexApkSigner(apex_file, container_pw, codename_to_api_level_map) apex_file = apk_signer.ProcessApexFile(apk_keys, payload_key, signing_args) # 2a. Extract and sign the APEX_PAYLOAD_IMAGE entry with the given # payload_key. payload_dir = common.MakeTempDir(prefix='apex-payload-') with zipfile.ZipFile(apex_file) as apex_fd: payload_file = apex_fd.extract(APEX_PAYLOAD_IMAGE, payload_dir) zip_items = apex_fd.namelist() payload_info = ParseApexPayloadInfo(avbtool, payload_file) if no_hashtree is None: no_hashtree = payload_info.get("Tree Size", 0) == 0 SignApexPayload( avbtool, payload_file, payload_key, payload_info['apex.key'], payload_info['Algorithm'], payload_info['Salt'], payload_info['Hash Algorithm'], no_hashtree, signing_args) # 2b. Update the embedded payload public key. payload_public_key = common.ExtractAvbPublicKey(avbtool, payload_key) common.ZipDelete(apex_file, APEX_PAYLOAD_IMAGE) if APEX_PUBKEY in zip_items: common.ZipDelete(apex_file, APEX_PUBKEY) apex_zip = zipfile.ZipFile(apex_file, 'a', allowZip64=True) common.ZipWrite(apex_zip, payload_file, arcname=APEX_PAYLOAD_IMAGE) common.ZipWrite(apex_zip, payload_public_key, arcname=APEX_PUBKEY) common.ZipClose(apex_zip) # 3. Sign the APEX container with container_key. signed_apex = common.MakeTempFile(prefix='apex-container-', suffix='.apex') # Specify the 4K alignment when calling SignApk. extra_signapk_args = OPTIONS.extra_signapk_args[:] extra_signapk_args.extend(['-a', '4096', '--align-file-size']) password = container_pw.get(container_key) if container_pw else None common.SignFile( apex_file, signed_apex, container_key, password, codename_to_api_level_map=codename_to_api_level_map, extra_signapk_args=extra_signapk_args) return signed_apex
def main(argv): common.SignFile(argv[1], argv[2], argv[0], None, whole_file=True)
def SignApex(apex_data, payload_key, container_key, container_pw, codename_to_api_level_map, signing_args=None): """Signs the current APEX with the given payload/container keys. Args: apex_data: Raw APEX data. payload_key: The path to payload signing key (w/ extension). container_key: The path to container signing key (w/o extension). container_pw: The matching password of the container_key, or None. codename_to_api_level_map: A dict that maps from codename to API level. signing_args: Additional args to be passed to the payload signer. Returns: The path to the signed APEX file. """ apex_file = common.MakeTempFile(prefix='apex-', suffix='.apex') with open(apex_file, 'wb') as apex_fp: apex_fp.write(apex_data) APEX_PAYLOAD_IMAGE = 'apex_payload.img' APEX_PUBKEY = 'apex_pubkey' # 1a. Extract and sign the APEX_PAYLOAD_IMAGE entry with the given # payload_key. payload_dir = common.MakeTempDir(prefix='apex-payload-') with zipfile.ZipFile(apex_file) as apex_fd: payload_file = apex_fd.extract(APEX_PAYLOAD_IMAGE, payload_dir) zip_items = apex_fd.namelist() payload_info = ParseApexPayloadInfo(payload_file) SignApexPayload(payload_file, payload_key, payload_info['apex.key'], payload_info['Algorithm'], payload_info['Salt'], signing_args) # 1b. Update the embedded payload public key. payload_public_key = common.ExtractAvbPublicKey(payload_key) common.ZipDelete(apex_file, APEX_PAYLOAD_IMAGE) if APEX_PUBKEY in zip_items: common.ZipDelete(apex_file, APEX_PUBKEY) apex_zip = zipfile.ZipFile(apex_file, 'a') common.ZipWrite(apex_zip, payload_file, arcname=APEX_PAYLOAD_IMAGE) common.ZipWrite(apex_zip, payload_public_key, arcname=APEX_PUBKEY) common.ZipClose(apex_zip) # 2. Align the files at page boundary (same as in apexer). aligned_apex = common.MakeTempFile(prefix='apex-container-', suffix='.apex') common.RunAndCheckOutput( ['zipalign', '-f', '4096', apex_file, aligned_apex]) # 3. Sign the APEX container with container_key. signed_apex = common.MakeTempFile(prefix='apex-container-', suffix='.apex') # Specify the 4K alignment when calling SignApk. extra_signapk_args = OPTIONS.extra_signapk_args[:] extra_signapk_args.extend(['-a', '4096']) common.SignFile(aligned_apex, signed_apex, container_key, container_pw, codename_to_api_level_map=codename_to_api_level_map, extra_signapk_args=extra_signapk_args) return signed_apex