Loading tools/releasetools/check_target_files_signatures.py +63 −54 Original line number Original line Diff line number Diff line Loading @@ -39,8 +39,11 @@ Usage: check_target_file_signatures [flags] target_files """ """ from __future__ import print_function import logging import logging import os import os import os.path import re import re import subprocess import subprocess import sys import sys Loading @@ -49,7 +52,7 @@ import zipfile import common import common if sys.hexversion < 0x02070000: if sys.hexversion < 0x02070000: print >> sys.stderr, "Python 2.7 or newer is required." print("Python 2.7 or newer is required.", file=sys.stderr) sys.exit(1) sys.exit(1) Loading @@ -65,8 +68,10 @@ logger = logging.getLogger(__name__) class MyZipInfo(zipfile.ZipInfo): class MyZipInfo(zipfile.ZipInfo): def _decodeExtra(self): def _decodeExtra(self): pass pass zipfile.ZipInfo = MyZipInfo zipfile.ZipInfo = MyZipInfo OPTIONS = common.OPTIONS OPTIONS = common.OPTIONS OPTIONS.text = False OPTIONS.text = False Loading @@ -76,28 +81,34 @@ OPTIONS.local_cert_dirs = ("vendor", "build") PROBLEMS = [] PROBLEMS = [] PROBLEM_PREFIX = [] PROBLEM_PREFIX = [] def AddProblem(msg): def AddProblem(msg): PROBLEMS.append(" ".join(PROBLEM_PREFIX) + " " + msg) PROBLEMS.append(" ".join(PROBLEM_PREFIX) + " " + msg) def Push(msg): def Push(msg): PROBLEM_PREFIX.append(msg) PROBLEM_PREFIX.append(msg) def Pop(): def Pop(): PROBLEM_PREFIX.pop() PROBLEM_PREFIX.pop() def Banner(msg): def Banner(msg): print "-" * 70 print("-" * 70) print " ", msg print(" ", msg) print "-" * 70 print("-" * 70) def GetCertSubject(cert): def GetCertSubject(cert): p = common.Run(["openssl", "x509", "-inform", "DER", "-text"], p = common.Run(["openssl", "x509", "-inform", "DER", "-text"], stdin=subprocess.PIPE, stdin=subprocess.PIPE, stdout=subprocess.PIPE) stdout=subprocess.PIPE, universal_newlines=False) out, err = p.communicate(cert) out, err = p.communicate(cert) if err and not err.strip(): if err and not err.strip(): return "(error reading cert subject)" return "(error reading cert subject)" for line in out.split("\n"): for line in out.decode().split("\n"): line = line.strip() line = line.strip() if line.startswith("Subject:"): if line.startswith("Subject:"): return line[8:].strip() return line[8:].strip() Loading @@ -105,6 +116,7 @@ def GetCertSubject(cert): class CertDB(object): class CertDB(object): def __init__(self): def __init__(self): self.certs = {} self.certs = {} Loading Loading @@ -132,13 +144,13 @@ class CertDB(object): to_load.extend(certs) to_load.extend(certs) for i in to_load: for i in to_load: f = open(i) with open(i) as f: cert = common.ParseCertificate(f.read()) cert = common.ParseCertificate(f.read()) f.close() name, _ = os.path.splitext(i) name, _ = os.path.splitext(i) name, _ = os.path.splitext(name) name, _ = os.path.splitext(name) self.Add(cert, name) self.Add(cert, name) ALL_CERTS = CertDB() ALL_CERTS = CertDB() Loading @@ -152,13 +164,14 @@ def CertFromPKCS7(data, filename): "-outform", "PEM", "-outform", "PEM", "-print_certs"], "-print_certs"], stdin=subprocess.PIPE, stdin=subprocess.PIPE, stdout=subprocess.PIPE) stdout=subprocess.PIPE, universal_newlines=False) out, err = p.communicate(data) out, err = p.communicate(data) if err and not err.strip(): if err and not err.strip(): AddProblem("error reading cert:\n" + err) AddProblem("error reading cert:\n" + err.decode()) return None return None cert = common.ParseCertificate(out) cert = common.ParseCertificate(out.decode()) if not cert: if not cert: AddProblem("error parsing cert output") AddProblem("error parsing cert output") return None return None Loading @@ -184,21 +197,19 @@ class APK(object): def RecordCerts(self, full_filename): def RecordCerts(self, full_filename): out = set() out = set() try: with zipfile.ZipFile(full_filename) as apk: f = open(full_filename) apk = zipfile.ZipFile(f, "r") pkcs7 = None pkcs7 = None for info in apk.infolist(): for info in apk.infolist(): if info.filename.startswith("META-INF/") and \ filename = info.filename (info.filename.endswith(".DSA") or info.filename.endswith(".RSA")): if (filename.startswith("META-INF/") and pkcs7 = apk.read(info.filename) info.filename.endswith((".DSA", ".RSA"))): cert = CertFromPKCS7(pkcs7, info.filename) pkcs7 = apk.read(filename) cert = CertFromPKCS7(pkcs7, filename) out.add(cert) out.add(cert) ALL_CERTS.Add(cert) ALL_CERTS.Add(cert) if not pkcs7: if not pkcs7: AddProblem("no signature") AddProblem("no signature") finally: f.close() self.certs = frozenset(out) self.certs = frozenset(out) def ReadManifest(self, full_filename): def ReadManifest(self, full_filename): Loading Loading @@ -247,8 +258,8 @@ class TargetFiles(object): # This is the list of wildcards of files we extract from |filename|. # This is the list of wildcards of files we extract from |filename|. apk_extensions = ['*.apk', '*.apex'] apk_extensions = ['*.apk', '*.apex'] self.certmap, compressed_extension = common.ReadApkCerts( with zipfile.ZipFile(filename) as input_zip: zipfile.ZipFile(filename)) self.certmap, compressed_extension = common.ReadApkCerts(input_zip) if compressed_extension: if compressed_extension: apk_extensions.append('*.apk' + compressed_extension) apk_extensions.append('*.apk' + compressed_extension) Loading Loading @@ -287,7 +298,7 @@ class TargetFiles(object): """Look for any instances where packages signed with different """Look for any instances where packages signed with different certs request the same sharedUserId.""" certs request the same sharedUserId.""" apks_by_uid = {} apks_by_uid = {} for apk in self.apks.itervalues(): for apk in self.apks.values(): if apk.shared_uid: if apk.shared_uid: apks_by_uid.setdefault(apk.shared_uid, []).append(apk) apks_by_uid.setdefault(apk.shared_uid, []).append(apk) Loading @@ -302,15 +313,15 @@ class TargetFiles(object): AddProblem("different cert sets for packages with uid %s" % (uid,)) AddProblem("different cert sets for packages with uid %s" % (uid,)) print "uid %s is shared by packages with different cert sets:" % (uid,) print("uid %s is shared by packages with different cert sets:" % (uid,)) for apk in apks: for apk in apks: print "%-*s [%s]" % (self.max_pkg_len, apk.package, apk.filename) print("%-*s [%s]" % (self.max_pkg_len, apk.package, apk.filename)) for cert in apk.certs: for cert in apk.certs: print " ", ALL_CERTS.Get(cert) print(" ", ALL_CERTS.Get(cert)) print print() def CheckExternalSignatures(self): def CheckExternalSignatures(self): for apk_filename, certname in self.certmap.iteritems(): for apk_filename, certname in self.certmap.items(): if certname == "EXTERNAL": if certname == "EXTERNAL": # Apps marked EXTERNAL should be signed with the test key # Apps marked EXTERNAL should be signed with the test key # during development, then manually re-signed after # during development, then manually re-signed after Loading @@ -326,25 +337,25 @@ class TargetFiles(object): def PrintCerts(self): def PrintCerts(self): """Display a table of packages grouped by cert.""" """Display a table of packages grouped by cert.""" by_cert = {} by_cert = {} for apk in self.apks.itervalues(): for apk in self.apks.values(): for cert in apk.certs: for cert in apk.certs: by_cert.setdefault(cert, []).append((apk.package, apk)) by_cert.setdefault(cert, []).append((apk.package, apk)) order = [(-len(v), k) for (k, v) in by_cert.iteritems()] order = [(-len(v), k) for (k, v) in by_cert.items()] order.sort() order.sort() for _, cert in order: for _, cert in order: print "%s:" % (ALL_CERTS.Get(cert),) print("%s:" % (ALL_CERTS.Get(cert),)) apks = by_cert[cert] apks = by_cert[cert] apks.sort() apks.sort() for _, apk in apks: for _, apk in apks: if apk.shared_uid: if apk.shared_uid: print " %-*s %-*s [%s]" % (self.max_fn_len, apk.filename, print(" %-*s %-*s [%s]" % (self.max_fn_len, apk.filename, self.max_pkg_len, apk.package, self.max_pkg_len, apk.package, apk.shared_uid) apk.shared_uid)) else: else: print " %-*s %s" % (self.max_fn_len, apk.filename, apk.package) print(" %-*s %s" % (self.max_fn_len, apk.filename, apk.package)) print print() def CompareWith(self, other): def CompareWith(self, other): """Look for instances where a given package that exists in both """Look for instances where a given package that exists in both Loading @@ -365,12 +376,12 @@ class TargetFiles(object): by_certpair.setdefault((other.apks[i].certs, by_certpair.setdefault((other.apks[i].certs, self.apks[i].certs), []).append(i) self.apks[i].certs), []).append(i) else: else: print "%s [%s]: new APK (not in comparison target_files)" % ( print("%s [%s]: new APK (not in comparison target_files)" % ( i, self.apks[i].filename) i, self.apks[i].filename)) else: else: if i in other.apks: if i in other.apks: print "%s [%s]: removed APK (only in comparison target_files)" % ( print("%s [%s]: removed APK (only in comparison target_files)" % ( i, other.apks[i].filename) i, other.apks[i].filename)) if by_certpair: if by_certpair: AddProblem("some APKs changed certs") AddProblem("some APKs changed certs") Loading @@ -378,23 +389,23 @@ class TargetFiles(object): for (old, new), packages in sorted(by_certpair.items()): for (old, new), packages in sorted(by_certpair.items()): for i, o in enumerate(old): for i, o in enumerate(old): if i == 0: if i == 0: print "was", ALL_CERTS.Get(o) print("was", ALL_CERTS.Get(o)) else: else: print " ", ALL_CERTS.Get(o) print(" ", ALL_CERTS.Get(o)) for i, n in enumerate(new): for i, n in enumerate(new): if i == 0: if i == 0: print "now", ALL_CERTS.Get(n) print("now", ALL_CERTS.Get(n)) else: else: print " ", ALL_CERTS.Get(n) print(" ", ALL_CERTS.Get(n)) for i in sorted(packages): for i in sorted(packages): old_fn = other.apks[i].filename old_fn = other.apks[i].filename new_fn = self.apks[i].filename new_fn = self.apks[i].filename if old_fn == new_fn: if old_fn == new_fn: print " %-*s [%s]" % (max_pkg_len, i, old_fn) print(" %-*s [%s]" % (max_pkg_len, i, old_fn)) else: else: print " %-*s [was: %s; now: %s]" % (max_pkg_len, i, print(" %-*s [was: %s; now: %s]" % (max_pkg_len, i, old_fn, new_fn) old_fn, new_fn)) print print() def main(argv): def main(argv): Loading Loading @@ -451,9 +462,9 @@ def main(argv): target_files.CompareWith(compare_files) target_files.CompareWith(compare_files) if PROBLEMS: if PROBLEMS: print "%d problem(s) found:\n" % (len(PROBLEMS),) print("%d problem(s) found:\n" % (len(PROBLEMS),)) for p in PROBLEMS: for p in PROBLEMS: print p print(p) return 1 return 1 return 0 return 0 Loading @@ -464,9 +475,7 @@ if __name__ == '__main__': r = main(sys.argv[1:]) r = main(sys.argv[1:]) sys.exit(r) sys.exit(r) except common.ExternalError as e: except common.ExternalError as e: print print("\n ERROR: %s\n" % (e,)) print " ERROR: %s" % (e,) print sys.exit(1) sys.exit(1) finally: finally: common.Cleanup() common.Cleanup() Loading
tools/releasetools/check_target_files_signatures.py +63 −54 Original line number Original line Diff line number Diff line Loading @@ -39,8 +39,11 @@ Usage: check_target_file_signatures [flags] target_files """ """ from __future__ import print_function import logging import logging import os import os import os.path import re import re import subprocess import subprocess import sys import sys Loading @@ -49,7 +52,7 @@ import zipfile import common import common if sys.hexversion < 0x02070000: if sys.hexversion < 0x02070000: print >> sys.stderr, "Python 2.7 or newer is required." print("Python 2.7 or newer is required.", file=sys.stderr) sys.exit(1) sys.exit(1) Loading @@ -65,8 +68,10 @@ logger = logging.getLogger(__name__) class MyZipInfo(zipfile.ZipInfo): class MyZipInfo(zipfile.ZipInfo): def _decodeExtra(self): def _decodeExtra(self): pass pass zipfile.ZipInfo = MyZipInfo zipfile.ZipInfo = MyZipInfo OPTIONS = common.OPTIONS OPTIONS = common.OPTIONS OPTIONS.text = False OPTIONS.text = False Loading @@ -76,28 +81,34 @@ OPTIONS.local_cert_dirs = ("vendor", "build") PROBLEMS = [] PROBLEMS = [] PROBLEM_PREFIX = [] PROBLEM_PREFIX = [] def AddProblem(msg): def AddProblem(msg): PROBLEMS.append(" ".join(PROBLEM_PREFIX) + " " + msg) PROBLEMS.append(" ".join(PROBLEM_PREFIX) + " " + msg) def Push(msg): def Push(msg): PROBLEM_PREFIX.append(msg) PROBLEM_PREFIX.append(msg) def Pop(): def Pop(): PROBLEM_PREFIX.pop() PROBLEM_PREFIX.pop() def Banner(msg): def Banner(msg): print "-" * 70 print("-" * 70) print " ", msg print(" ", msg) print "-" * 70 print("-" * 70) def GetCertSubject(cert): def GetCertSubject(cert): p = common.Run(["openssl", "x509", "-inform", "DER", "-text"], p = common.Run(["openssl", "x509", "-inform", "DER", "-text"], stdin=subprocess.PIPE, stdin=subprocess.PIPE, stdout=subprocess.PIPE) stdout=subprocess.PIPE, universal_newlines=False) out, err = p.communicate(cert) out, err = p.communicate(cert) if err and not err.strip(): if err and not err.strip(): return "(error reading cert subject)" return "(error reading cert subject)" for line in out.split("\n"): for line in out.decode().split("\n"): line = line.strip() line = line.strip() if line.startswith("Subject:"): if line.startswith("Subject:"): return line[8:].strip() return line[8:].strip() Loading @@ -105,6 +116,7 @@ def GetCertSubject(cert): class CertDB(object): class CertDB(object): def __init__(self): def __init__(self): self.certs = {} self.certs = {} Loading Loading @@ -132,13 +144,13 @@ class CertDB(object): to_load.extend(certs) to_load.extend(certs) for i in to_load: for i in to_load: f = open(i) with open(i) as f: cert = common.ParseCertificate(f.read()) cert = common.ParseCertificate(f.read()) f.close() name, _ = os.path.splitext(i) name, _ = os.path.splitext(i) name, _ = os.path.splitext(name) name, _ = os.path.splitext(name) self.Add(cert, name) self.Add(cert, name) ALL_CERTS = CertDB() ALL_CERTS = CertDB() Loading @@ -152,13 +164,14 @@ def CertFromPKCS7(data, filename): "-outform", "PEM", "-outform", "PEM", "-print_certs"], "-print_certs"], stdin=subprocess.PIPE, stdin=subprocess.PIPE, stdout=subprocess.PIPE) stdout=subprocess.PIPE, universal_newlines=False) out, err = p.communicate(data) out, err = p.communicate(data) if err and not err.strip(): if err and not err.strip(): AddProblem("error reading cert:\n" + err) AddProblem("error reading cert:\n" + err.decode()) return None return None cert = common.ParseCertificate(out) cert = common.ParseCertificate(out.decode()) if not cert: if not cert: AddProblem("error parsing cert output") AddProblem("error parsing cert output") return None return None Loading @@ -184,21 +197,19 @@ class APK(object): def RecordCerts(self, full_filename): def RecordCerts(self, full_filename): out = set() out = set() try: with zipfile.ZipFile(full_filename) as apk: f = open(full_filename) apk = zipfile.ZipFile(f, "r") pkcs7 = None pkcs7 = None for info in apk.infolist(): for info in apk.infolist(): if info.filename.startswith("META-INF/") and \ filename = info.filename (info.filename.endswith(".DSA") or info.filename.endswith(".RSA")): if (filename.startswith("META-INF/") and pkcs7 = apk.read(info.filename) info.filename.endswith((".DSA", ".RSA"))): cert = CertFromPKCS7(pkcs7, info.filename) pkcs7 = apk.read(filename) cert = CertFromPKCS7(pkcs7, filename) out.add(cert) out.add(cert) ALL_CERTS.Add(cert) ALL_CERTS.Add(cert) if not pkcs7: if not pkcs7: AddProblem("no signature") AddProblem("no signature") finally: f.close() self.certs = frozenset(out) self.certs = frozenset(out) def ReadManifest(self, full_filename): def ReadManifest(self, full_filename): Loading Loading @@ -247,8 +258,8 @@ class TargetFiles(object): # This is the list of wildcards of files we extract from |filename|. # This is the list of wildcards of files we extract from |filename|. apk_extensions = ['*.apk', '*.apex'] apk_extensions = ['*.apk', '*.apex'] self.certmap, compressed_extension = common.ReadApkCerts( with zipfile.ZipFile(filename) as input_zip: zipfile.ZipFile(filename)) self.certmap, compressed_extension = common.ReadApkCerts(input_zip) if compressed_extension: if compressed_extension: apk_extensions.append('*.apk' + compressed_extension) apk_extensions.append('*.apk' + compressed_extension) Loading Loading @@ -287,7 +298,7 @@ class TargetFiles(object): """Look for any instances where packages signed with different """Look for any instances where packages signed with different certs request the same sharedUserId.""" certs request the same sharedUserId.""" apks_by_uid = {} apks_by_uid = {} for apk in self.apks.itervalues(): for apk in self.apks.values(): if apk.shared_uid: if apk.shared_uid: apks_by_uid.setdefault(apk.shared_uid, []).append(apk) apks_by_uid.setdefault(apk.shared_uid, []).append(apk) Loading @@ -302,15 +313,15 @@ class TargetFiles(object): AddProblem("different cert sets for packages with uid %s" % (uid,)) AddProblem("different cert sets for packages with uid %s" % (uid,)) print "uid %s is shared by packages with different cert sets:" % (uid,) print("uid %s is shared by packages with different cert sets:" % (uid,)) for apk in apks: for apk in apks: print "%-*s [%s]" % (self.max_pkg_len, apk.package, apk.filename) print("%-*s [%s]" % (self.max_pkg_len, apk.package, apk.filename)) for cert in apk.certs: for cert in apk.certs: print " ", ALL_CERTS.Get(cert) print(" ", ALL_CERTS.Get(cert)) print print() def CheckExternalSignatures(self): def CheckExternalSignatures(self): for apk_filename, certname in self.certmap.iteritems(): for apk_filename, certname in self.certmap.items(): if certname == "EXTERNAL": if certname == "EXTERNAL": # Apps marked EXTERNAL should be signed with the test key # Apps marked EXTERNAL should be signed with the test key # during development, then manually re-signed after # during development, then manually re-signed after Loading @@ -326,25 +337,25 @@ class TargetFiles(object): def PrintCerts(self): def PrintCerts(self): """Display a table of packages grouped by cert.""" """Display a table of packages grouped by cert.""" by_cert = {} by_cert = {} for apk in self.apks.itervalues(): for apk in self.apks.values(): for cert in apk.certs: for cert in apk.certs: by_cert.setdefault(cert, []).append((apk.package, apk)) by_cert.setdefault(cert, []).append((apk.package, apk)) order = [(-len(v), k) for (k, v) in by_cert.iteritems()] order = [(-len(v), k) for (k, v) in by_cert.items()] order.sort() order.sort() for _, cert in order: for _, cert in order: print "%s:" % (ALL_CERTS.Get(cert),) print("%s:" % (ALL_CERTS.Get(cert),)) apks = by_cert[cert] apks = by_cert[cert] apks.sort() apks.sort() for _, apk in apks: for _, apk in apks: if apk.shared_uid: if apk.shared_uid: print " %-*s %-*s [%s]" % (self.max_fn_len, apk.filename, print(" %-*s %-*s [%s]" % (self.max_fn_len, apk.filename, self.max_pkg_len, apk.package, self.max_pkg_len, apk.package, apk.shared_uid) apk.shared_uid)) else: else: print " %-*s %s" % (self.max_fn_len, apk.filename, apk.package) print(" %-*s %s" % (self.max_fn_len, apk.filename, apk.package)) print print() def CompareWith(self, other): def CompareWith(self, other): """Look for instances where a given package that exists in both """Look for instances where a given package that exists in both Loading @@ -365,12 +376,12 @@ class TargetFiles(object): by_certpair.setdefault((other.apks[i].certs, by_certpair.setdefault((other.apks[i].certs, self.apks[i].certs), []).append(i) self.apks[i].certs), []).append(i) else: else: print "%s [%s]: new APK (not in comparison target_files)" % ( print("%s [%s]: new APK (not in comparison target_files)" % ( i, self.apks[i].filename) i, self.apks[i].filename)) else: else: if i in other.apks: if i in other.apks: print "%s [%s]: removed APK (only in comparison target_files)" % ( print("%s [%s]: removed APK (only in comparison target_files)" % ( i, other.apks[i].filename) i, other.apks[i].filename)) if by_certpair: if by_certpair: AddProblem("some APKs changed certs") AddProblem("some APKs changed certs") Loading @@ -378,23 +389,23 @@ class TargetFiles(object): for (old, new), packages in sorted(by_certpair.items()): for (old, new), packages in sorted(by_certpair.items()): for i, o in enumerate(old): for i, o in enumerate(old): if i == 0: if i == 0: print "was", ALL_CERTS.Get(o) print("was", ALL_CERTS.Get(o)) else: else: print " ", ALL_CERTS.Get(o) print(" ", ALL_CERTS.Get(o)) for i, n in enumerate(new): for i, n in enumerate(new): if i == 0: if i == 0: print "now", ALL_CERTS.Get(n) print("now", ALL_CERTS.Get(n)) else: else: print " ", ALL_CERTS.Get(n) print(" ", ALL_CERTS.Get(n)) for i in sorted(packages): for i in sorted(packages): old_fn = other.apks[i].filename old_fn = other.apks[i].filename new_fn = self.apks[i].filename new_fn = self.apks[i].filename if old_fn == new_fn: if old_fn == new_fn: print " %-*s [%s]" % (max_pkg_len, i, old_fn) print(" %-*s [%s]" % (max_pkg_len, i, old_fn)) else: else: print " %-*s [was: %s; now: %s]" % (max_pkg_len, i, print(" %-*s [was: %s; now: %s]" % (max_pkg_len, i, old_fn, new_fn) old_fn, new_fn)) print print() def main(argv): def main(argv): Loading Loading @@ -451,9 +462,9 @@ def main(argv): target_files.CompareWith(compare_files) target_files.CompareWith(compare_files) if PROBLEMS: if PROBLEMS: print "%d problem(s) found:\n" % (len(PROBLEMS),) print("%d problem(s) found:\n" % (len(PROBLEMS),)) for p in PROBLEMS: for p in PROBLEMS: print p print(p) return 1 return 1 return 0 return 0 Loading @@ -464,9 +475,7 @@ if __name__ == '__main__': r = main(sys.argv[1:]) r = main(sys.argv[1:]) sys.exit(r) sys.exit(r) except common.ExternalError as e: except common.ExternalError as e: print print("\n ERROR: %s\n" % (e,)) print " ERROR: %s" % (e,) print sys.exit(1) sys.exit(1) finally: finally: common.Cleanup() common.Cleanup()