From eb338efd2eae20962c7ca75baf161be540b3d664 Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Wed, 20 May 2009 16:50:49 -0700 Subject: [PATCH] make sure package keys are consistent with shared users All APKs that want to share a given user id must be signed with the same key. Look inside each APK for what (if any) shared user id it requests, and error out if any with the same shared user are being signed with different keys. --- tools/releasetools/sign_target_files_apks | 108 +++++++++++++++++----- 1 file changed, 86 insertions(+), 22 deletions(-) diff --git a/tools/releasetools/sign_target_files_apks b/tools/releasetools/sign_target_files_apks index b3bfaee8c..844182d68 100755 --- a/tools/releasetools/sign_target_files_apks +++ b/tools/releasetools/sign_target_files_apks @@ -101,6 +101,85 @@ def GetApkCerts(tf_zip): return certmap +def CheckAllApksSigned(input_tf_zip, apk_key_map): + """Check that all the APKs we want to sign have keys specified, and + error out if they don't.""" + unknown_apks = [] + for info in input_tf_zip.infolist(): + if info.filename.endswith(".apk"): + name = os.path.basename(info.filename) + if name not in apk_key_map: + unknown_apks.append(name) + if unknown_apks: + print "ERROR: no key specified for:\n\n ", + print "\n ".join(unknown_apks) + print "\nUse '-e =' to specify a key (which may be an" + print "empty string to not sign this apk)." + sys.exit(1) + + +def SharedUserForApk(data): + tmp = tempfile.NamedTemporaryFile() + tmp.write(data) + tmp.flush() + + p = common.Run(["aapt", "dump", "xmltree", tmp.name, "AndroidManifest.xml"], + stdout=subprocess.PIPE) + data, _ = p.communicate() + if p.returncode != 0: + raise ExternalError("failed to run aapt dump") + lines = data.split("\n") + for i in lines: + m = re.match(r'^\s*A: android:sharedUserId\([0-9a-fx]*\)="([^"]*)" .*$', i) + if m: + return m.group(1) + return None + + +def CheckSharedUserIdsConsistent(input_tf_zip, apk_key_map): + """Check that all packages that request the same shared user id are + going to be signed with the same key.""" + + shared_user_apks = {} + maxlen = 0 + + for info in input_tf_zip.infolist(): + if info.filename.endswith(".apk"): + data = input_tf_zip.read(info.filename) + + name = os.path.basename(info.filename) + shared_user = SharedUserForApk(data) + key = apk_key_map[name] + maxlen = max(maxlen, len(key)) + + if shared_user is not None: + shared_user_apks.setdefault( + shared_user, {}).setdefault(key, []).append(name) + + errors = [] + for k, v in shared_user_apks.iteritems(): + # each shared user should have exactly one key used for all the + # apks that want that user. + if len(v) > 1: + errors.append((k, v)) + + if not errors: return + + print "ERROR: shared user inconsistency. All apks wanting to use" + print " a given shared user must be signed with the same key." + print + errors.sort() + for user, keys in errors: + print 'shared user id "%s":' % (user,) + for key, apps in keys.iteritems(): + print ' %-*s %s' % (maxlen, key, apps[0]) + for a in apps[1:]: + print (' ' * (maxlen+5)) + a + print + + sys.exit(1) + + def SignApk(data, keyname, pw): unsigned = tempfile.NamedTemporaryFile() unsigned.write(data) @@ -117,31 +196,11 @@ def SignApk(data, keyname, pw): return data -def SignApks(input_tf_zip, output_tf_zip): - apk_key_map = GetApkCerts(input_tf_zip) - +def SignApks(input_tf_zip, output_tf_zip, apk_key_map, key_passwords): maxsize = max([len(os.path.basename(i.filename)) for i in input_tf_zip.infolist() if i.filename.endswith('.apk')]) - # Check that all the APKs we want to sign have keys specified, and - # error out if they don't. Do this before prompting for key - # passwords in case we're going to fail anyway. - unknown_apks = [] - for info in input_tf_zip.infolist(): - if info.filename.endswith(".apk"): - name = os.path.basename(info.filename) - if name not in apk_key_map: - unknown_apks.append(name) - if unknown_apks: - print "ERROR: no key specified for:\n\n ", - print "\n ".join(unknown_apks) - print "\nUse '-e =' to specify a key (which may be an" - print "empty string to not sign this apk)." - sys.exit(1) - - key_passwords = common.GetKeyPasswords(set(apk_key_map.values())) - for info in input_tf_zip.infolist(): data = input_tf_zip.read(info.filename) out_info = copy.copy(info) @@ -289,7 +348,12 @@ def main(argv): input_zip = zipfile.ZipFile(args[0], "r") output_zip = zipfile.ZipFile(args[1], "w") - SignApks(input_zip, output_zip) + apk_key_map = GetApkCerts(input_zip) + CheckAllApksSigned(input_zip, apk_key_map) + CheckSharedUserIdsConsistent(input_zip, apk_key_map) + + key_passwords = common.GetKeyPasswords(set(apk_key_map.values())) + SignApks(input_zip, output_zip, apk_key_map, key_passwords) if OPTIONS.replace_ota_keys: ReplaceOtaKeys(input_zip, output_zip)