Loading tools/releasetools/check_target_files_signatures.py +29 −2 Original line number Diff line number Diff line Loading @@ -235,12 +235,40 @@ class TargetFiles(object): self.certmap = None def LoadZipFile(self, filename): d, z = common.UnzipTemp(filename, ['*.apk']) # First read the APK certs file to figure out whether there are compressed # APKs in the archive. If we do have compressed APKs in the archive, then we # must decompress them individually before we perform any analysis. # This is the list of wildcards of files we extract from |filename|. apk_extensions = ['*.apk'] self.certmap, compressed_extension = common.ReadApkCerts(zipfile.ZipFile(filename, "r")) if compressed_extension: apk_extensions.append("*.apk" + compressed_extension) d, z = common.UnzipTemp(filename, apk_extensions) try: self.apks = {} self.apks_by_basename = {} for dirpath, _, filenames in os.walk(d): for fn in filenames: # Decompress compressed APKs before we begin processing them. if compressed_extension and fn.endswith(compressed_extension): # First strip the compressed extension from the file. uncompressed_fn = fn[:-len(compressed_extension)] # Decompress the compressed file to the output file. common.Gunzip(os.path.join(dirpath, fn), os.path.join(dirpath, uncompressed_fn)) # Finally, delete the compressed file and use the uncompressed file # for further processing. Note that the deletion is not strictly required, # but is done here to ensure that we're not using too much space in # the temporary directory. os.remove(os.path.join(dirpath, fn)) fn = uncompressed_fn if fn.endswith(".apk"): fullname = os.path.join(dirpath, fn) displayname = fullname[len(d)+1:] Loading @@ -253,7 +281,6 @@ class TargetFiles(object): finally: shutil.rmtree(d) self.certmap = common.ReadApkCerts(z) z.close() def CheckSharedUids(self): Loading tools/releasetools/common.py +34 −5 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ import copy import errno import getopt import getpass import gzip import imp import os import platform Loading Loading @@ -552,6 +553,13 @@ def GetBootableImage(name, prebuilt_name, unpack_dir, tree_subdir, return None def Gunzip(in_filename, out_filename): """Gunzip the given gzip compressed file to a given output file. """ with gzip.open(in_filename, "rb") as in_file, open(out_filename, "wb") as out_file: shutil.copyfileobj(in_file, out_file) def UnzipTemp(filename, pattern=None): """Unzip the given archive into a temporary directory and return the name. Loading Loading @@ -757,16 +765,26 @@ def CheckSize(data, target, info_dict): def ReadApkCerts(tf_zip): """Given a target_files ZipFile, parse the META/apkcerts.txt file and return a {package: cert} dict.""" and return a tuple with the following elements: (1) a dictionary that maps packages to certs (based on the "certificate" and "private_key" attributes in the file. (2) A string representing the extension of compressed APKs in the target files (e.g ".gz" ".bro").""" certmap = {} compressed_extension = None for line in tf_zip.read("META/apkcerts.txt").split("\n"): line = line.strip() if not line: continue m = re.match(r'^name="(.*)"\s+certificate="(.*)"\s+' r'private_key="(.*)"$', line) m = re.match(r'^name="(?P<NAME>.*)"\s+certificate="(?P<CERT>.*)"\s+' r'private_key="(?P<PRIVKEY>.*?)"(\s+compressed="(?P<COMPRESSED>.*)")?$', line) if m: name, cert, privkey = m.groups() matches = m.groupdict() cert = matches["CERT"] privkey = matches["PRIVKEY"] name = matches["NAME"] this_compressed_extension = matches["COMPRESSED"] public_key_suffix_len = len(OPTIONS.public_key_suffix) private_key_suffix_len = len(OPTIONS.private_key_suffix) if cert in SPECIAL_CERT_STRINGS and not privkey: Loading @@ -777,7 +795,18 @@ def ReadApkCerts(tf_zip): certmap[name] = cert[:-public_key_suffix_len] else: raise ValueError("failed to parse line from apkcerts.txt:\n" + line) return certmap if this_compressed_extension: # Make sure that all the values in the compression map have the same # extension. We don't support multiple compression methods in the same # system image. if compressed_extension: if this_compressed_extension != compressed_extension: raise ValueError("multiple compressed extensions : %s vs %s", (compressed_extension, this_compressed_extension)) else: compressed_extension = this_compressed_extension return (certmap, ("." + compressed_extension) if compressed_extension else None) COMMON_DOCSTRING = """ Loading tools/releasetools/sign_target_files_apks.py +58 −14 Original line number Diff line number Diff line Loading @@ -100,8 +100,10 @@ import base64 import cStringIO import copy import errno import gzip import os import re import shutil import stat import subprocess import tempfile Loading @@ -124,9 +126,7 @@ OPTIONS.avb_keys = {} OPTIONS.avb_algorithms = {} OPTIONS.avb_extra_args = {} def GetApkCerts(tf_zip): certmap = common.ReadApkCerts(tf_zip) def GetApkCerts(certmap): # apply the key remapping to the contents of the file for apk, cert in certmap.iteritems(): certmap[apk] = OPTIONS.key_map.get(cert, cert) Loading @@ -140,13 +140,19 @@ def GetApkCerts(tf_zip): return certmap def CheckAllApksSigned(input_tf_zip, apk_key_map): def CheckAllApksSigned(input_tf_zip, apk_key_map, compressed_extension): """Check that all the APKs we want to sign have keys specified, and error out if they don't.""" unknown_apks = [] compressed_apk_extension = None if compressed_extension: compressed_apk_extension = ".apk" + compressed_extension for info in input_tf_zip.infolist(): if info.filename.endswith(".apk"): if (info.filename.endswith(".apk") or (compressed_apk_extension and info.filename.endswith(compressed_apk_extension))): name = os.path.basename(info.filename) if compressed_apk_extension and name.endswith(compressed_apk_extension): name = name[:-len(compressed_extension)] if name not in apk_key_map: unknown_apks.append(name) if unknown_apks: Loading @@ -157,11 +163,25 @@ def CheckAllApksSigned(input_tf_zip, apk_key_map): sys.exit(1) def SignApk(data, keyname, pw, platform_api_level, codename_to_api_level_map): 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 Loading @@ -186,7 +206,18 @@ def SignApk(data, keyname, pw, platform_api_level, codename_to_api_level_map): 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() Loading @@ -195,11 +226,17 @@ def SignApk(data, keyname, pw, platform_api_level, codename_to_api_level_map): def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info, apk_key_map, key_passwords, platform_api_level, codename_to_api_level_map): codename_to_api_level_map, compressed_extension): compressed_apk_extension = None if compressed_extension: compressed_apk_extension = ".apk" + compressed_extension maxsize = max([len(os.path.basename(i.filename)) for i in input_tf_zip.infolist() if i.filename.endswith('.apk')]) if i.filename.endswith('.apk') or (compressed_apk_extension and i.filename.endswith(compressed_apk_extension))]) system_root_image = misc_info.get("system_root_image") == "true" for info in input_tf_zip.infolist(): Loading @@ -210,13 +247,18 @@ def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info, out_info = copy.copy(info) # Sign APKs. if info.filename.endswith(".apk"): if (info.filename.endswith(".apk") or (compressed_apk_extension and info.filename.endswith(compressed_apk_extension))): is_compressed = compressed_extension and info.filename.endswith(compressed_apk_extension) name = os.path.basename(info.filename) if is_compressed: name = name[:-len(compressed_extension)] key = apk_key_map[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) 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. Loading Loading @@ -748,8 +790,9 @@ def main(argv): BuildKeyMap(misc_info, key_mapping_options) apk_key_map = GetApkCerts(input_zip) CheckAllApksSigned(input_zip, apk_key_map) certmap, compressed_extension = common.ReadApkCerts(input_zip) apk_key_map = GetApkCerts(certmap) CheckAllApksSigned(input_zip, apk_key_map, compressed_extension) key_passwords = common.GetKeyPasswords(set(apk_key_map.values())) platform_api_level, _ = GetApiLevelAndCodename(input_zip) Loading @@ -758,7 +801,8 @@ def main(argv): ProcessTargetFiles(input_zip, output_zip, misc_info, apk_key_map, key_passwords, platform_api_level, codename_to_api_level_map) codename_to_api_level_map, compressed_extension) common.ZipClose(input_zip) common.ZipClose(output_zip) Loading Loading
tools/releasetools/check_target_files_signatures.py +29 −2 Original line number Diff line number Diff line Loading @@ -235,12 +235,40 @@ class TargetFiles(object): self.certmap = None def LoadZipFile(self, filename): d, z = common.UnzipTemp(filename, ['*.apk']) # First read the APK certs file to figure out whether there are compressed # APKs in the archive. If we do have compressed APKs in the archive, then we # must decompress them individually before we perform any analysis. # This is the list of wildcards of files we extract from |filename|. apk_extensions = ['*.apk'] self.certmap, compressed_extension = common.ReadApkCerts(zipfile.ZipFile(filename, "r")) if compressed_extension: apk_extensions.append("*.apk" + compressed_extension) d, z = common.UnzipTemp(filename, apk_extensions) try: self.apks = {} self.apks_by_basename = {} for dirpath, _, filenames in os.walk(d): for fn in filenames: # Decompress compressed APKs before we begin processing them. if compressed_extension and fn.endswith(compressed_extension): # First strip the compressed extension from the file. uncompressed_fn = fn[:-len(compressed_extension)] # Decompress the compressed file to the output file. common.Gunzip(os.path.join(dirpath, fn), os.path.join(dirpath, uncompressed_fn)) # Finally, delete the compressed file and use the uncompressed file # for further processing. Note that the deletion is not strictly required, # but is done here to ensure that we're not using too much space in # the temporary directory. os.remove(os.path.join(dirpath, fn)) fn = uncompressed_fn if fn.endswith(".apk"): fullname = os.path.join(dirpath, fn) displayname = fullname[len(d)+1:] Loading @@ -253,7 +281,6 @@ class TargetFiles(object): finally: shutil.rmtree(d) self.certmap = common.ReadApkCerts(z) z.close() def CheckSharedUids(self): Loading
tools/releasetools/common.py +34 −5 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ import copy import errno import getopt import getpass import gzip import imp import os import platform Loading Loading @@ -552,6 +553,13 @@ def GetBootableImage(name, prebuilt_name, unpack_dir, tree_subdir, return None def Gunzip(in_filename, out_filename): """Gunzip the given gzip compressed file to a given output file. """ with gzip.open(in_filename, "rb") as in_file, open(out_filename, "wb") as out_file: shutil.copyfileobj(in_file, out_file) def UnzipTemp(filename, pattern=None): """Unzip the given archive into a temporary directory and return the name. Loading Loading @@ -757,16 +765,26 @@ def CheckSize(data, target, info_dict): def ReadApkCerts(tf_zip): """Given a target_files ZipFile, parse the META/apkcerts.txt file and return a {package: cert} dict.""" and return a tuple with the following elements: (1) a dictionary that maps packages to certs (based on the "certificate" and "private_key" attributes in the file. (2) A string representing the extension of compressed APKs in the target files (e.g ".gz" ".bro").""" certmap = {} compressed_extension = None for line in tf_zip.read("META/apkcerts.txt").split("\n"): line = line.strip() if not line: continue m = re.match(r'^name="(.*)"\s+certificate="(.*)"\s+' r'private_key="(.*)"$', line) m = re.match(r'^name="(?P<NAME>.*)"\s+certificate="(?P<CERT>.*)"\s+' r'private_key="(?P<PRIVKEY>.*?)"(\s+compressed="(?P<COMPRESSED>.*)")?$', line) if m: name, cert, privkey = m.groups() matches = m.groupdict() cert = matches["CERT"] privkey = matches["PRIVKEY"] name = matches["NAME"] this_compressed_extension = matches["COMPRESSED"] public_key_suffix_len = len(OPTIONS.public_key_suffix) private_key_suffix_len = len(OPTIONS.private_key_suffix) if cert in SPECIAL_CERT_STRINGS and not privkey: Loading @@ -777,7 +795,18 @@ def ReadApkCerts(tf_zip): certmap[name] = cert[:-public_key_suffix_len] else: raise ValueError("failed to parse line from apkcerts.txt:\n" + line) return certmap if this_compressed_extension: # Make sure that all the values in the compression map have the same # extension. We don't support multiple compression methods in the same # system image. if compressed_extension: if this_compressed_extension != compressed_extension: raise ValueError("multiple compressed extensions : %s vs %s", (compressed_extension, this_compressed_extension)) else: compressed_extension = this_compressed_extension return (certmap, ("." + compressed_extension) if compressed_extension else None) COMMON_DOCSTRING = """ Loading
tools/releasetools/sign_target_files_apks.py +58 −14 Original line number Diff line number Diff line Loading @@ -100,8 +100,10 @@ import base64 import cStringIO import copy import errno import gzip import os import re import shutil import stat import subprocess import tempfile Loading @@ -124,9 +126,7 @@ OPTIONS.avb_keys = {} OPTIONS.avb_algorithms = {} OPTIONS.avb_extra_args = {} def GetApkCerts(tf_zip): certmap = common.ReadApkCerts(tf_zip) def GetApkCerts(certmap): # apply the key remapping to the contents of the file for apk, cert in certmap.iteritems(): certmap[apk] = OPTIONS.key_map.get(cert, cert) Loading @@ -140,13 +140,19 @@ def GetApkCerts(tf_zip): return certmap def CheckAllApksSigned(input_tf_zip, apk_key_map): def CheckAllApksSigned(input_tf_zip, apk_key_map, compressed_extension): """Check that all the APKs we want to sign have keys specified, and error out if they don't.""" unknown_apks = [] compressed_apk_extension = None if compressed_extension: compressed_apk_extension = ".apk" + compressed_extension for info in input_tf_zip.infolist(): if info.filename.endswith(".apk"): if (info.filename.endswith(".apk") or (compressed_apk_extension and info.filename.endswith(compressed_apk_extension))): name = os.path.basename(info.filename) if compressed_apk_extension and name.endswith(compressed_apk_extension): name = name[:-len(compressed_extension)] if name not in apk_key_map: unknown_apks.append(name) if unknown_apks: Loading @@ -157,11 +163,25 @@ def CheckAllApksSigned(input_tf_zip, apk_key_map): sys.exit(1) def SignApk(data, keyname, pw, platform_api_level, codename_to_api_level_map): 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 Loading @@ -186,7 +206,18 @@ def SignApk(data, keyname, pw, platform_api_level, codename_to_api_level_map): 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() Loading @@ -195,11 +226,17 @@ def SignApk(data, keyname, pw, platform_api_level, codename_to_api_level_map): def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info, apk_key_map, key_passwords, platform_api_level, codename_to_api_level_map): codename_to_api_level_map, compressed_extension): compressed_apk_extension = None if compressed_extension: compressed_apk_extension = ".apk" + compressed_extension maxsize = max([len(os.path.basename(i.filename)) for i in input_tf_zip.infolist() if i.filename.endswith('.apk')]) if i.filename.endswith('.apk') or (compressed_apk_extension and i.filename.endswith(compressed_apk_extension))]) system_root_image = misc_info.get("system_root_image") == "true" for info in input_tf_zip.infolist(): Loading @@ -210,13 +247,18 @@ def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info, out_info = copy.copy(info) # Sign APKs. if info.filename.endswith(".apk"): if (info.filename.endswith(".apk") or (compressed_apk_extension and info.filename.endswith(compressed_apk_extension))): is_compressed = compressed_extension and info.filename.endswith(compressed_apk_extension) name = os.path.basename(info.filename) if is_compressed: name = name[:-len(compressed_extension)] key = apk_key_map[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) 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. Loading Loading @@ -748,8 +790,9 @@ def main(argv): BuildKeyMap(misc_info, key_mapping_options) apk_key_map = GetApkCerts(input_zip) CheckAllApksSigned(input_zip, apk_key_map) certmap, compressed_extension = common.ReadApkCerts(input_zip) apk_key_map = GetApkCerts(certmap) CheckAllApksSigned(input_zip, apk_key_map, compressed_extension) key_passwords = common.GetKeyPasswords(set(apk_key_map.values())) platform_api_level, _ = GetApiLevelAndCodename(input_zip) Loading @@ -758,7 +801,8 @@ def main(argv): ProcessTargetFiles(input_zip, output_zip, misc_info, apk_key_map, key_passwords, platform_api_level, codename_to_api_level_map) codename_to_api_level_map, compressed_extension) common.ZipClose(input_zip) common.ZipClose(output_zip) Loading