sign_target_files_apks revision ad88c7ce4f3a65827d4cd5b5ed01324b3b368dd9
1eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker#!/usr/bin/env python 2eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker# 3eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker# Copyright (C) 2008 The Android Open Source Project 4eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker# 5eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker# Licensed under the Apache License, Version 2.0 (the "License"); 6eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker# you may not use this file except in compliance with the License. 7eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker# You may obtain a copy of the License at 8eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker# 9eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker# http://www.apache.org/licenses/LICENSE-2.0 10eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker# 11eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker# Unless required by applicable law or agreed to in writing, software 12eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker# distributed under the License is distributed on an "AS IS" BASIS, 13eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker# See the License for the specific language governing permissions and 15eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker# limitations under the License. 16eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 17eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker""" 18eef3944eb3673329b5e89cf188ac592805a0b08dDoug ZongkerSigns all the APK files in a target-files zipfile, producing a new 19eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkertarget-files zip. 20eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 21eef3944eb3673329b5e89cf188ac592805a0b08dDoug ZongkerUsage: sign_target_files_apks [flags] input_target_files output_target_files 22eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 23eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker -s (--signapk_jar) <path> 24eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker Path of the signapks.jar file used to sign an individual APK 25eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker file. 26eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 27eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker -e (--extra_apks) <name,name,...=key> 28eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker Add extra APK name/key pairs as though they appeared in 29ad88c7ce4f3a65827d4cd5b5ed01324b3b368dd9Doug Zongker apkcerts.txt (so mappings specified by -k and -d are applied). 30ad88c7ce4f3a65827d4cd5b5ed01324b3b368dd9Doug Zongker Keys specified in -e override any value for that app contained 31ad88c7ce4f3a65827d4cd5b5ed01324b3b368dd9Doug Zongker in the apkcerts.txt file. Option may be repeated to give 32ad88c7ce4f3a65827d4cd5b5ed01324b3b368dd9Doug Zongker multiple extra packages. 33eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 34eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker -k (--key_mapping) <src_key=dest_key> 35eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker Add a mapping from the key name as specified in apkcerts.txt (the 36eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker src_key) to the real key you wish to sign the package with 37eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker (dest_key). Option may be repeated to give multiple key 38eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker mappings. 39eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 40eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker -d (--default_key_mappings) <dir> 41eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker Set up the following key mappings: 42eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 43eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker build/target/product/security/testkey ==> $dir/releasekey 44eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker build/target/product/security/media ==> $dir/media 45eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker build/target/product/security/shared ==> $dir/shared 46eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker build/target/product/security/platform ==> $dir/platform 47eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 48eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker -d and -k options are added to the set of mappings in the order 49eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker in which they appear on the command line. 50eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker""" 51eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 52eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport sys 53eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 54eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerif sys.hexversion < 0x02040000: 55eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker print >> sys.stderr, "Python 2.4 or newer is required." 56eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker sys.exit(1) 57eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 58eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport os 59eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport re 60eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport subprocess 61eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport tempfile 62eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport zipfile 63eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 64eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport common 65eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 66eef3944eb3673329b5e89cf188ac592805a0b08dDoug ZongkerOPTIONS = common.OPTIONS 67eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 68eef3944eb3673329b5e89cf188ac592805a0b08dDoug ZongkerOPTIONS.extra_apks = {} 69eef3944eb3673329b5e89cf188ac592805a0b08dDoug ZongkerOPTIONS.key_map = {} 70eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 71eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 72eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerdef GetApkCerts(tf_zip): 73ad88c7ce4f3a65827d4cd5b5ed01324b3b368dd9Doug Zongker certmap = {} 74eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker for line in tf_zip.read("META/apkcerts.txt").split("\n"): 75eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker line = line.strip() 76eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if not line: continue 77eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker m = re.match(r'^name="(.*)"\s+certificate="(.*)\.x509\.pem"\s+' 78eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker r'private_key="\2\.pk8"$', line) 79eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if not m: 80eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker raise SigningError("failed to parse line from apkcerts.txt:\n" + line) 81eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker certmap[m.group(1)] = OPTIONS.key_map.get(m.group(2), m.group(2)) 82ad88c7ce4f3a65827d4cd5b5ed01324b3b368dd9Doug Zongker for apk, cert in OPTIONS.extra_apks.iteritems(): 83ad88c7ce4f3a65827d4cd5b5ed01324b3b368dd9Doug Zongker certmap[apk] = OPTIONS.key_map.get(cert, cert) 84eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker return certmap 85eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 86eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 87eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerdef SignApk(data, keyname, pw): 88eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker unsigned = tempfile.NamedTemporaryFile() 89eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker unsigned.write(data) 90eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker unsigned.flush() 91eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 92eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker signed = tempfile.NamedTemporaryFile() 93eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 94eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker common.SignFile(unsigned.name, signed.name, keyname, pw, align=4) 95eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 96eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker data = signed.read() 97eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker unsigned.close() 98eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker signed.close() 99eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 100eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker return data 101eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 102eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 103eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerdef SignApks(input_tf_zip, output_tf_zip): 104eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker apk_key_map = GetApkCerts(input_tf_zip) 105eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 106eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker key_passwords = common.GetKeyPasswords(set(apk_key_map.values())) 107eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 108eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker maxsize = max([len(os.path.basename(i.filename)) 109eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker for i in input_tf_zip.infolist() 110eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if i.filename.endswith('.apk')]) 111eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 112eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker for info in input_tf_zip.infolist(): 113eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker data = input_tf_zip.read(info.filename) 114eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if info.filename.endswith(".apk"): 115eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker name = os.path.basename(info.filename) 116eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker key = apk_key_map.get(name, None) 117eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if key is not None: 118eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker print "signing: %-*s (%s)" % (maxsize, name, key) 119eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker signed_data = SignApk(data, key, key_passwords[key]) 120eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker output_tf_zip.writestr(info, signed_data) 121eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker else: 122eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # an APK we're not supposed to sign. 123eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker print "skipping: %s" % (name,) 124eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker output_tf_zip.writestr(info, data) 125eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker elif info.filename == "SYSTEM/build.prop": 126eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # Change build fingerprint to reflect the fact that apps are signed. 127eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker m = re.search(r"ro\.build\.fingerprint=.*\b(test-keys)\b.*", data) 128eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if not m: 129eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker print 'WARNING: ro.build.fingerprint does not contain "test-keys"' 130eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker else: 131eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker data = data[:m.start(1)] + "release-keys" + data[m.end(1):] 132eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker m = re.search(r"ro\.build\.description=.*\b(test-keys)\b.*", data) 133eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if not m: 134eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker print 'WARNING: ro.build.description does not contain "test-keys"' 135eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker else: 136eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker data = data[:m.start(1)] + "release-keys" + data[m.end(1):] 137eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker output_tf_zip.writestr(info, data) 138eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker else: 139eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # a non-APK file; copy it verbatim 140eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker output_tf_zip.writestr(info, data) 141eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 142eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 143eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerdef main(argv): 144eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 145eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker def option_handler(o, a): 146eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if o in ("-s", "--signapk_jar"): 147eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker OPTIONS.signapk_jar = a 148eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker elif o in ("-e", "--extra_apks"): 149eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker names, key = a.split("=") 150eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker names = names.split(",") 151eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker for n in names: 152eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker OPTIONS.extra_apks[n] = key 153eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker elif o in ("-d", "--default_key_mappings"): 154eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker OPTIONS.key_map.update({ 155eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker "build/target/product/security/testkey": "%s/releasekey" % (a,), 156eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker "build/target/product/security/media": "%s/media" % (a,), 157eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker "build/target/product/security/shared": "%s/shared" % (a,), 158eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker "build/target/product/security/platform": "%s/platform" % (a,), 159eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker }) 160eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker elif o in ("-k", "--key_mapping"): 161eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker s, d = a.split("=") 162eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker OPTIONS.key_map[s] = d 163eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker else: 164eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker return False 165eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker return True 166eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 167eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker args = common.ParseOptions(argv, __doc__, 168eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker extra_opts="s:e:d:k:", 169eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker extra_long_opts=["signapk_jar=", 170eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker "extra_apks=", 171eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker "default_key_mappings=", 172eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker "key_mapping="], 173eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker extra_option_handler=option_handler) 174eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 175eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if len(args) != 2: 176eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker common.Usage(__doc__) 177eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker sys.exit(1) 178eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 179eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker input_zip = zipfile.ZipFile(args[0], "r") 180eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker output_zip = zipfile.ZipFile(args[1], "w") 181eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 182eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker SignApks(input_zip, output_zip) 183eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 184eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker input_zip.close() 185eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker output_zip.close() 186eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 187eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker print "done." 188eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 189eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 190eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerif __name__ == '__main__': 191eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker try: 192eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker main(sys.argv[1:]) 193eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker except common.ExternalError, e: 194eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker print 195eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker print " ERROR: %s" % (e,) 196eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker print 197eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker sys.exit(1) 198