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  -e  (--extra_apks)  <name,name,...=key>
24eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      Add extra APK name/key pairs as though they appeared in
25ad88c7ce4f3a65827d4cd5b5ed01324b3b368dd9Doug Zongker      apkcerts.txt (so mappings specified by -k and -d are applied).
26ad88c7ce4f3a65827d4cd5b5ed01324b3b368dd9Doug Zongker      Keys specified in -e override any value for that app contained
27ad88c7ce4f3a65827d4cd5b5ed01324b3b368dd9Doug Zongker      in the apkcerts.txt file.  Option may be repeated to give
28ad88c7ce4f3a65827d4cd5b5ed01324b3b368dd9Doug Zongker      multiple extra packages.
29eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
30eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  -k  (--key_mapping)  <src_key=dest_key>
31eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      Add a mapping from the key name as specified in apkcerts.txt (the
32eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      src_key) to the real key you wish to sign the package with
33eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      (dest_key).  Option may be repeated to give multiple key
34eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      mappings.
35eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
36eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  -d  (--default_key_mappings)  <dir>
37eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      Set up the following key mappings:
38eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
39831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker        $devkey/devkey    ==>  $dir/releasekey
40831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker        $devkey/testkey   ==>  $dir/releasekey
41831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker        $devkey/media     ==>  $dir/media
42831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker        $devkey/shared    ==>  $dir/shared
43831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker        $devkey/platform  ==>  $dir/platform
44831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker
45831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker      where $devkey is the directory part of the value of
46831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker      default_system_dev_certificate from the input target-files's
47831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker      META/misc_info.txt.  (Defaulting to "build/target/product/security"
48831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker      if the value is not present in misc_info.
49eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
50eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      -d and -k options are added to the set of mappings in the order
51eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      in which they appear on the command line.
528e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker
538e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  -o  (--replace_ota_keys)
548e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker      Replace the certificate (public key) used by OTA package
558e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker      verification with the one specified in the input target_files
568e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker      zip (in the META/otakeys.txt file).  Key remapping (-k and -d)
578e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker      is performed on this key.
5817aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker
59ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker  -t  (--tag_changes)  <+tag>,<-tag>,...
60ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker      Comma-separated list of changes to make to the set of tags (in
61ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker      the last component of the build fingerprint).  Prefix each with
62ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker      '+' or '-' to indicate whether that tag should be added or
63ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker      removed.  Changes are processed in the order they appear.
64831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker      Default value is "-test-keys,-dev-keys,+release-keys".
65ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker
66eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker"""
67eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
68eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport sys
69eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
70cf6d5a90740e50e03d9f16c6fd449d90d396f924Doug Zongkerif sys.hexversion < 0x02070000:
71cf6d5a90740e50e03d9f16c6fd449d90d396f924Doug Zongker  print >> sys.stderr, "Python 2.7 or newer is required."
72eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  sys.exit(1)
73eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
74817c574d753191c52acd5787da02bb853d4ac090Robert Craigimport base64
758e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongkerimport cStringIO
768e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongkerimport copy
77817c574d753191c52acd5787da02bb853d4ac090Robert Craigimport errno
78eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport os
79eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport re
80412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongkerimport shutil
81eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport subprocess
82eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport tempfile
83eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport zipfile
84eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
853c84f569487c4e59baa332be33b5430fdefb76b3Doug Zongkerimport add_img_to_target_files
86eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport common
87eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
88eef3944eb3673329b5e89cf188ac592805a0b08dDoug ZongkerOPTIONS = common.OPTIONS
89eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
90eef3944eb3673329b5e89cf188ac592805a0b08dDoug ZongkerOPTIONS.extra_apks = {}
91eef3944eb3673329b5e89cf188ac592805a0b08dDoug ZongkerOPTIONS.key_map = {}
928e931bf999693cac54c99deb1ef668d0e6164ecfDoug ZongkerOPTIONS.replace_ota_keys = False
93f19b365cc9021104586d65385d246db06639fc46Geremy CondraOPTIONS.replace_verity_public_key = False
94f19b365cc9021104586d65385d246db06639fc46Geremy CondraOPTIONS.replace_verity_private_key = False
95831840e51b0403671f746ebc32090b7d6e548c08Doug ZongkerOPTIONS.tag_changes = ("-test-keys", "-dev-keys", "+release-keys")
96eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
97eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerdef GetApkCerts(tf_zip):
98f6a53aa5f24878ad9098409ed3d3f41bb5c63fb5Doug Zongker  certmap = common.ReadApkCerts(tf_zip)
99f6a53aa5f24878ad9098409ed3d3f41bb5c63fb5Doug Zongker
100f6a53aa5f24878ad9098409ed3d3f41bb5c63fb5Doug Zongker  # apply the key remapping to the contents of the file
101f6a53aa5f24878ad9098409ed3d3f41bb5c63fb5Doug Zongker  for apk, cert in certmap.iteritems():
102f6a53aa5f24878ad9098409ed3d3f41bb5c63fb5Doug Zongker    certmap[apk] = OPTIONS.key_map.get(cert, cert)
103f6a53aa5f24878ad9098409ed3d3f41bb5c63fb5Doug Zongker
104f6a53aa5f24878ad9098409ed3d3f41bb5c63fb5Doug Zongker  # apply all the -e options, overriding anything in the file
105ad88c7ce4f3a65827d4cd5b5ed01324b3b368dd9Doug Zongker  for apk, cert in OPTIONS.extra_apks.iteritems():
106decf995c5956e6f64f858d1c4e51a3f3b9829a51Doug Zongker    if not cert:
107decf995c5956e6f64f858d1c4e51a3f3b9829a51Doug Zongker      cert = "PRESIGNED"
108ad88c7ce4f3a65827d4cd5b5ed01324b3b368dd9Doug Zongker    certmap[apk] = OPTIONS.key_map.get(cert, cert)
109f6a53aa5f24878ad9098409ed3d3f41bb5c63fb5Doug Zongker
110eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  return certmap
111eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
112eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
113eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongkerdef CheckAllApksSigned(input_tf_zip, apk_key_map):
114eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker  """Check that all the APKs we want to sign have keys specified, and
115eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker  error out if they don't."""
116eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker  unknown_apks = []
117eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker  for info in input_tf_zip.infolist():
118eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker    if info.filename.endswith(".apk"):
119eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker      name = os.path.basename(info.filename)
120eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker      if name not in apk_key_map:
121eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker        unknown_apks.append(name)
122eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker  if unknown_apks:
123eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker    print "ERROR: no key specified for:\n\n ",
124eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker    print "\n  ".join(unknown_apks)
125eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker    print "\nUse '-e <apkname>=' to specify a key (which may be an"
126eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker    print "empty string to not sign this apk)."
127eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker    sys.exit(1)
128eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker
129eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker
130eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerdef SignApk(data, keyname, pw):
131eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  unsigned = tempfile.NamedTemporaryFile()
132eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  unsigned.write(data)
133eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  unsigned.flush()
134eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
135eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  signed = tempfile.NamedTemporaryFile()
136eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
137eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  common.SignFile(unsigned.name, signed.name, keyname, pw, align=4)
138eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
139eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  data = signed.read()
140eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  unsigned.close()
141eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  signed.close()
142eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
143eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  return data
144eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
145eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
146412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongkerdef ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
147412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker                       apk_key_map, key_passwords):
148dc2661afe263de054be8ecf5f1252a6fbde776c6Michael Runge
149eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  maxsize = max([len(os.path.basename(i.filename))
150eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker                 for i in input_tf_zip.infolist()
151eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker                 if i.filename.endswith('.apk')])
152412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker  rebuild_recovery = False
153412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker
154412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker  tmpdir = tempfile.mkdtemp()
155412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker  def write_to_temp(fn, attr, data):
156412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker    fn = os.path.join(tmpdir, fn)
157412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker    if fn.endswith("/"):
158412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker      fn = os.path.join(tmpdir, fn)
159412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker      os.mkdir(fn)
160412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker    else:
161412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker      d = os.path.dirname(fn)
162412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker      if d and not os.path.exists(d):
163412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker        os.makedirs(d)
164412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker
165412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker      if attr >> 16 == 0xa1ff:
166412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker        os.symlink(data, fn)
167412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker      else:
168412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker        with open(fn, "wb") as f:
169412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker          f.write(data)
170eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
171eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  for info in input_tf_zip.infolist():
1723c84f569487c4e59baa332be33b5430fdefb76b3Doug Zongker    if info.filename.startswith("IMAGES/"): continue
1733c84f569487c4e59baa332be33b5430fdefb76b3Doug Zongker
174eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    data = input_tf_zip.read(info.filename)
1758e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker    out_info = copy.copy(info)
176412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker
177f19b365cc9021104586d65385d246db06639fc46Geremy Condra    if (info.filename == "META/misc_info.txt" and
178947894f87edd9ae3429d33011447346240200fdbMichael Runge        OPTIONS.replace_verity_private_key):
179f19b365cc9021104586d65385d246db06639fc46Geremy Condra      ReplaceVerityPrivateKey(input_tf_zip, output_tf_zip, misc_info, OPTIONS.replace_verity_private_key[1])
180f19b365cc9021104586d65385d246db06639fc46Geremy Condra    elif (info.filename == "BOOT/RAMDISK/verity_key" and
181947894f87edd9ae3429d33011447346240200fdbMichael Runge        OPTIONS.replace_verity_public_key):
182f19b365cc9021104586d65385d246db06639fc46Geremy Condra      ReplaceVerityPublicKey(output_tf_zip, OPTIONS.replace_verity_public_key[1])
183f19b365cc9021104586d65385d246db06639fc46Geremy Condra    elif (info.filename.startswith("BOOT/") or
184412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker        info.filename.startswith("RECOVERY/") or
185412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker        info.filename.startswith("META/") or
186412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker        info.filename == "SYSTEM/etc/recovery-resource.dat"):
187412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker      write_to_temp(info.filename, info.external_attr, data)
188412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker
189eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    if info.filename.endswith(".apk"):
190eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      name = os.path.basename(info.filename)
19143874f8c864972b9dae7e4927aa347455b774c94Doug Zongker      key = apk_key_map[name]
192f6a53aa5f24878ad9098409ed3d3f41bb5c63fb5Doug Zongker      if key not in common.SPECIAL_CERT_STRINGS:
19343874f8c864972b9dae7e4927aa347455b774c94Doug Zongker        print "    signing: %-*s (%s)" % (maxsize, name, key)
194eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        signed_data = SignApk(data, key, key_passwords[key])
1958e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker        output_tf_zip.writestr(out_info, signed_data)
196eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      else:
197eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        # an APK we're not supposed to sign.
19843874f8c864972b9dae7e4927aa347455b774c94Doug Zongker        print "NOT signing: %s" % (name,)
1998e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker        output_tf_zip.writestr(out_info, data)
2008e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker    elif info.filename in ("SYSTEM/build.prop",
2018e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker                           "RECOVERY/RAMDISK/default.prop"):
20217aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker      print "rewriting %s:" % (info.filename,)
203dc2661afe263de054be8ecf5f1252a6fbde776c6Michael Runge      new_data = RewriteProps(data, misc_info)
20417aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker      output_tf_zip.writestr(out_info, new_data)
205412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker      if info.filename == "RECOVERY/RAMDISK/default.prop":
206412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker        write_to_temp(info.filename, info.external_attr, new_data)
207817c574d753191c52acd5787da02bb853d4ac090Robert Craig    elif info.filename.endswith("mac_permissions.xml"):
208817c574d753191c52acd5787da02bb853d4ac090Robert Craig      print "rewriting %s with new keys." % (info.filename,)
209817c574d753191c52acd5787da02bb853d4ac090Robert Craig      new_data = ReplaceCerts(data)
210817c574d753191c52acd5787da02bb853d4ac090Robert Craig      output_tf_zip.writestr(out_info, new_data)
211412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker    elif info.filename in ("SYSTEM/recovery-from-boot.p",
212412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker                           "SYSTEM/bin/install-recovery.sh"):
213412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker      rebuild_recovery = True
214412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker    elif (OPTIONS.replace_ota_keys and
215412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker          info.filename in ("RECOVERY/RAMDISK/res/keys",
216412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker                            "SYSTEM/etc/security/otacerts.zip")):
217412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker      # don't copy these files if we're regenerating them below
218412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker      pass
219947894f87edd9ae3429d33011447346240200fdbMichael Runge    elif (OPTIONS.replace_verity_private_key and
220f19b365cc9021104586d65385d246db06639fc46Geremy Condra          info.filename == "META/misc_info.txt"):
221f19b365cc9021104586d65385d246db06639fc46Geremy Condra      pass
222947894f87edd9ae3429d33011447346240200fdbMichael Runge    elif (OPTIONS.replace_verity_public_key and
223f19b365cc9021104586d65385d246db06639fc46Geremy Condra          info.filename == "BOOT/RAMDISK/verity_key"):
224f19b365cc9021104586d65385d246db06639fc46Geremy Condra      pass
225eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    else:
226eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      # a non-APK file; copy it verbatim
2278e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker      output_tf_zip.writestr(out_info, data)
2288e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker
229412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker  if OPTIONS.replace_ota_keys:
230412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker    new_recovery_keys = ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info)
231412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker    if new_recovery_keys:
232412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker      write_to_temp("RECOVERY/RAMDISK/res/keys", 0755 << 16, new_recovery_keys)
233412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker
234412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker  if rebuild_recovery:
235412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker    recovery_img = common.GetBootableImage(
236412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker        "recovery.img", "recovery.img", tmpdir, "RECOVERY", info_dict=misc_info)
237412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker    boot_img = common.GetBootableImage(
238412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker        "boot.img", "boot.img", tmpdir, "BOOT", info_dict=misc_info)
239412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker
240412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker    def output_sink(fn, data):
241412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker      output_tf_zip.writestr("SYSTEM/"+fn, data)
242412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker
243412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker    common.MakeRecoveryPatch(tmpdir, output_sink, recovery_img, boot_img,
244412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker                             info_dict=misc_info)
245412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker
246412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker  shutil.rmtree(tmpdir)
247412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker
2488e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker
249817c574d753191c52acd5787da02bb853d4ac090Robert Craigdef ReplaceCerts(data):
250817c574d753191c52acd5787da02bb853d4ac090Robert Craig  """Given a string of data, replace all occurences of a set
251817c574d753191c52acd5787da02bb853d4ac090Robert Craig  of X509 certs with a newer set of X509 certs and return
252817c574d753191c52acd5787da02bb853d4ac090Robert Craig  the updated data string."""
253817c574d753191c52acd5787da02bb853d4ac090Robert Craig  for old, new in OPTIONS.key_map.iteritems():
254817c574d753191c52acd5787da02bb853d4ac090Robert Craig    try:
255817c574d753191c52acd5787da02bb853d4ac090Robert Craig      if OPTIONS.verbose:
256817c574d753191c52acd5787da02bb853d4ac090Robert Craig        print "    Replacing %s.x509.pem with %s.x509.pem" % (old, new)
257817c574d753191c52acd5787da02bb853d4ac090Robert Craig      f = open(old + ".x509.pem")
258817c574d753191c52acd5787da02bb853d4ac090Robert Craig      old_cert16 = base64.b16encode(common.ParseCertificate(f.read())).lower()
259817c574d753191c52acd5787da02bb853d4ac090Robert Craig      f.close()
260817c574d753191c52acd5787da02bb853d4ac090Robert Craig      f = open(new + ".x509.pem")
261817c574d753191c52acd5787da02bb853d4ac090Robert Craig      new_cert16 = base64.b16encode(common.ParseCertificate(f.read())).lower()
262817c574d753191c52acd5787da02bb853d4ac090Robert Craig      f.close()
263817c574d753191c52acd5787da02bb853d4ac090Robert Craig      # Only match entire certs.
264817c574d753191c52acd5787da02bb853d4ac090Robert Craig      pattern = "\\b"+old_cert16+"\\b"
265817c574d753191c52acd5787da02bb853d4ac090Robert Craig      (data, num) = re.subn(pattern, new_cert16, data, flags=re.IGNORECASE)
266817c574d753191c52acd5787da02bb853d4ac090Robert Craig      if OPTIONS.verbose:
267817c574d753191c52acd5787da02bb853d4ac090Robert Craig        print "    Replaced %d occurence(s) of %s.x509.pem with " \
268817c574d753191c52acd5787da02bb853d4ac090Robert Craig            "%s.x509.pem" % (num, old, new)
269817c574d753191c52acd5787da02bb853d4ac090Robert Craig    except IOError, e:
270817c574d753191c52acd5787da02bb853d4ac090Robert Craig      if (e.errno == errno.ENOENT and not OPTIONS.verbose):
271817c574d753191c52acd5787da02bb853d4ac090Robert Craig        continue
272817c574d753191c52acd5787da02bb853d4ac090Robert Craig
273817c574d753191c52acd5787da02bb853d4ac090Robert Craig      print "    Error accessing %s. %s. Skip replacing %s.x509.pem " \
274817c574d753191c52acd5787da02bb853d4ac090Robert Craig          "with %s.x509.pem." % (e.filename, e.strerror, old, new)
275817c574d753191c52acd5787da02bb853d4ac090Robert Craig
276817c574d753191c52acd5787da02bb853d4ac090Robert Craig  return data
277817c574d753191c52acd5787da02bb853d4ac090Robert Craig
278817c574d753191c52acd5787da02bb853d4ac090Robert Craig
279c09abc8103a4c029cc2c6d59226a2a74be57d082Doug Zongkerdef EditTags(tags):
280c09abc8103a4c029cc2c6d59226a2a74be57d082Doug Zongker  """Given a string containing comma-separated tags, apply the edits
281c09abc8103a4c029cc2c6d59226a2a74be57d082Doug Zongker  specified in OPTIONS.tag_changes and return the updated string."""
282c09abc8103a4c029cc2c6d59226a2a74be57d082Doug Zongker  tags = set(tags.split(","))
283c09abc8103a4c029cc2c6d59226a2a74be57d082Doug Zongker  for ch in OPTIONS.tag_changes:
284c09abc8103a4c029cc2c6d59226a2a74be57d082Doug Zongker    if ch[0] == "-":
285c09abc8103a4c029cc2c6d59226a2a74be57d082Doug Zongker      tags.discard(ch[1:])
286c09abc8103a4c029cc2c6d59226a2a74be57d082Doug Zongker    elif ch[0] == "+":
287c09abc8103a4c029cc2c6d59226a2a74be57d082Doug Zongker      tags.add(ch[1:])
288c09abc8103a4c029cc2c6d59226a2a74be57d082Doug Zongker  return ",".join(sorted(tags))
289c09abc8103a4c029cc2c6d59226a2a74be57d082Doug Zongker
290c09abc8103a4c029cc2c6d59226a2a74be57d082Doug Zongker
291dc2661afe263de054be8ecf5f1252a6fbde776c6Michael Rungedef RewriteProps(data, misc_info):
29217aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker  output = []
29317aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker  for line in data.split("\n"):
29417aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker    line = line.strip()
29517aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker    original_line = line
296dc2661afe263de054be8ecf5f1252a6fbde776c6Michael Runge    if line and line[0] != '#' and "=" in line:
29717aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker      key, value = line.split("=", 1)
298dc2661afe263de054be8ecf5f1252a6fbde776c6Michael Runge      if (key == "ro.build.fingerprint"
299dc2661afe263de054be8ecf5f1252a6fbde776c6Michael Runge          and misc_info.get("oem_fingerprint_properties") is None):
300dc2661afe263de054be8ecf5f1252a6fbde776c6Michael Runge        pieces = value.split("/")
301dc2661afe263de054be8ecf5f1252a6fbde776c6Michael Runge        pieces[-1] = EditTags(pieces[-1])
302dc2661afe263de054be8ecf5f1252a6fbde776c6Michael Runge        value = "/".join(pieces)
303dc2661afe263de054be8ecf5f1252a6fbde776c6Michael Runge      elif (key == "ro.build.thumbprint"
304dc2661afe263de054be8ecf5f1252a6fbde776c6Michael Runge          and misc_info.get("oem_fingerprint_properties") is not None):
305c09abc8103a4c029cc2c6d59226a2a74be57d082Doug Zongker        pieces = value.split("/")
306c09abc8103a4c029cc2c6d59226a2a74be57d082Doug Zongker        pieces[-1] = EditTags(pieces[-1])
307c09abc8103a4c029cc2c6d59226a2a74be57d082Doug Zongker        value = "/".join(pieces)
30817aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker      elif key == "ro.build.description":
309c09abc8103a4c029cc2c6d59226a2a74be57d082Doug Zongker        pieces = value.split(" ")
31017aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker        assert len(pieces) == 5
311c09abc8103a4c029cc2c6d59226a2a74be57d082Doug Zongker        pieces[-1] = EditTags(pieces[-1])
312c09abc8103a4c029cc2c6d59226a2a74be57d082Doug Zongker        value = " ".join(pieces)
313c09abc8103a4c029cc2c6d59226a2a74be57d082Doug Zongker      elif key == "ro.build.tags":
314c09abc8103a4c029cc2c6d59226a2a74be57d082Doug Zongker        value = EditTags(value)
315a8608a7f7cee388192780f8988b5dc5966423eefDoug Zongker      elif key == "ro.build.display.id":
316a8608a7f7cee388192780f8988b5dc5966423eefDoug Zongker        # change, eg, "JWR66N dev-keys" to "JWR66N"
317a8608a7f7cee388192780f8988b5dc5966423eefDoug Zongker        value = value.split()
318dc2661afe263de054be8ecf5f1252a6fbde776c6Michael Runge        if len(value) > 1 and value[-1].endswith("-keys"):
31973d5abbd3f26d086ab4082f66b322f28a32bf7e5Andrew Boie          value.pop()
32073d5abbd3f26d086ab4082f66b322f28a32bf7e5Andrew Boie        value = " ".join(value)
321c09abc8103a4c029cc2c6d59226a2a74be57d082Doug Zongker      line = key + "=" + value
32217aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker    if line != original_line:
32317aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker      print "  replace: ", original_line
32417aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker      print "     with: ", line
32517aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker    output.append(line)
32617aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker  return "\n".join(output) + "\n"
32717aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker
32817aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker
329831840e51b0403671f746ebc32090b7d6e548c08Doug Zongkerdef ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info):
3308e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  try:
3318e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker    keylist = input_tf_zip.read("META/otakeys.txt").split()
3328e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  except KeyError:
333a28acc6972ce35e9dfab061f175e229859d3e4dbT.R. Fullhart    raise common.ExternalError("can't read META/otakeys.txt from input")
3348e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker
335e121d6acf47c3056e079ff62c82171e889cec3e0Doug Zongker  extra_recovery_keys = misc_info.get("extra_recovery_keys", None)
336e121d6acf47c3056e079ff62c82171e889cec3e0Doug Zongker  if extra_recovery_keys:
337e121d6acf47c3056e079ff62c82171e889cec3e0Doug Zongker    extra_recovery_keys = [OPTIONS.key_map.get(k, k) + ".x509.pem"
338e121d6acf47c3056e079ff62c82171e889cec3e0Doug Zongker                           for k in extra_recovery_keys.split()]
339e121d6acf47c3056e079ff62c82171e889cec3e0Doug Zongker    if extra_recovery_keys:
340e121d6acf47c3056e079ff62c82171e889cec3e0Doug Zongker      print "extra recovery-only key(s): " + ", ".join(extra_recovery_keys)
341e121d6acf47c3056e079ff62c82171e889cec3e0Doug Zongker  else:
342e121d6acf47c3056e079ff62c82171e889cec3e0Doug Zongker    extra_recovery_keys = []
343e121d6acf47c3056e079ff62c82171e889cec3e0Doug Zongker
3448e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  mapped_keys = []
3458e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  for k in keylist:
3468e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker    m = re.match(r"^(.*)\.x509\.pem$", k)
3478e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker    if not m:
348412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker      raise common.ExternalError(
349412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker          "can't parse \"%s\" from META/otakeys.txt" % (k,))
3508e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker    k = m.group(1)
3518e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker    mapped_keys.append(OPTIONS.key_map.get(k, k) + ".x509.pem")
3528e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker
353e05628cc8df4ec4b69befa9652d81eb81f0ab008Doug Zongker  if mapped_keys:
354e05628cc8df4ec4b69befa9652d81eb81f0ab008Doug Zongker    print "using:\n   ", "\n   ".join(mapped_keys)
355e05628cc8df4ec4b69befa9652d81eb81f0ab008Doug Zongker    print "for OTA package verification"
356e05628cc8df4ec4b69befa9652d81eb81f0ab008Doug Zongker  else:
357831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker    devkey = misc_info.get("default_system_dev_certificate",
358831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker                           "build/target/product/security/testkey")
359e05628cc8df4ec4b69befa9652d81eb81f0ab008Doug Zongker    mapped_keys.append(
360831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker        OPTIONS.key_map.get(devkey, devkey) + ".x509.pem")
361e05628cc8df4ec4b69befa9652d81eb81f0ab008Doug Zongker    print "META/otakeys.txt has no keys; using", mapped_keys[0]
3628e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker
3638e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  # recovery uses a version of the key that has been slightly
3648e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  # predigested (by DumpPublicKey.java) and put in res/keys.
365e121d6acf47c3056e079ff62c82171e889cec3e0Doug Zongker  # extra_recovery_keys are used only in recovery.
3668e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker
367602a84e0bbf1807a9403cfa50184241f6fc035c4Doug Zongker  p = common.Run(["java", "-jar",
368602a84e0bbf1807a9403cfa50184241f6fc035c4Doug Zongker                  os.path.join(OPTIONS.search_path, "framework", "dumpkey.jar")]
369e121d6acf47c3056e079ff62c82171e889cec3e0Doug Zongker                 + mapped_keys + extra_recovery_keys,
3708e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker                 stdout=subprocess.PIPE)
371412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker  new_recovery_keys, _ = p.communicate()
3728e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  if p.returncode != 0:
373a28acc6972ce35e9dfab061f175e229859d3e4dbT.R. Fullhart    raise common.ExternalError("failed to run dumpkeys")
374412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker  common.ZipWriteStr(output_tf_zip, "RECOVERY/RAMDISK/res/keys",
375412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker                     new_recovery_keys)
3768e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker
3778e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  # SystemUpdateActivity uses the x509.pem version of the keys, but
3788e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  # put into a zipfile system/etc/security/otacerts.zip.
379e121d6acf47c3056e079ff62c82171e889cec3e0Doug Zongker  # We DO NOT include the extra_recovery_keys (if any) here.
3808e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker
3818e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  tempfile = cStringIO.StringIO()
3828e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  certs_zip = zipfile.ZipFile(tempfile, "w")
3838e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  for k in mapped_keys:
3848e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker    certs_zip.write(k)
3858e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  certs_zip.close()
386048e7ca15f6391681490ce564bc71194adf146aaDoug Zongker  common.ZipWriteStr(output_tf_zip, "SYSTEM/etc/security/otacerts.zip",
387048e7ca15f6391681490ce564bc71194adf146aaDoug Zongker                     tempfile.getvalue())
388eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
389412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker  return new_recovery_keys
390412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker
391f19b365cc9021104586d65385d246db06639fc46Geremy Condradef ReplaceVerityPublicKey(targetfile_zip, key_path):
392f19b365cc9021104586d65385d246db06639fc46Geremy Condra  print "Replacing verity public key with %s" % key_path
393f19b365cc9021104586d65385d246db06639fc46Geremy Condra  with open(key_path) as f:
394f19b365cc9021104586d65385d246db06639fc46Geremy Condra    common.ZipWriteStr(targetfile_zip, "BOOT/RAMDISK/verity_key", f.read())
395f19b365cc9021104586d65385d246db06639fc46Geremy Condra
396f19b365cc9021104586d65385d246db06639fc46Geremy Condradef ReplaceVerityPrivateKey(targetfile_input_zip, targetfile_output_zip, misc_info, key_path):
397f19b365cc9021104586d65385d246db06639fc46Geremy Condra  print "Replacing verity private key with %s" % key_path
398f19b365cc9021104586d65385d246db06639fc46Geremy Condra  current_key = misc_info["verity_key"]
399f19b365cc9021104586d65385d246db06639fc46Geremy Condra  original_misc_info = targetfile_input_zip.read("META/misc_info.txt")
400f19b365cc9021104586d65385d246db06639fc46Geremy Condra  new_misc_info = original_misc_info.replace(current_key, key_path)
401f19b365cc9021104586d65385d246db06639fc46Geremy Condra  common.ZipWriteStr(targetfile_output_zip, "META/misc_info.txt", new_misc_info)
402eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
403831840e51b0403671f746ebc32090b7d6e548c08Doug Zongkerdef BuildKeyMap(misc_info, key_mapping_options):
404831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker  for s, d in key_mapping_options:
405831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker    if s is None:   # -d option
406831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker      devkey = misc_info.get("default_system_dev_certificate",
407831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker                             "build/target/product/security/testkey")
408831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker      devkeydir = os.path.dirname(devkey)
409831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker
410831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker      OPTIONS.key_map.update({
411831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker          devkeydir + "/testkey":  d + "/releasekey",
412831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker          devkeydir + "/devkey":   d + "/releasekey",
413831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker          devkeydir + "/media":    d + "/media",
414831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker          devkeydir + "/shared":   d + "/shared",
415831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker          devkeydir + "/platform": d + "/platform",
416831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker          })
417831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker    else:
418831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker      OPTIONS.key_map[s] = d
419831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker
420831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker
421eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerdef main(argv):
422eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
423831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker  key_mapping_options = []
424831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker
425eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  def option_handler(o, a):
42605d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker    if o in ("-e", "--extra_apks"):
427eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      names, key = a.split("=")
428eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      names = names.split(",")
429eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      for n in names:
430eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        OPTIONS.extra_apks[n] = key
431eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    elif o in ("-d", "--default_key_mappings"):
432831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker      key_mapping_options.append((None, a))
433eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    elif o in ("-k", "--key_mapping"):
434831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker      key_mapping_options.append(a.split("=", 1))
4358e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker    elif o in ("-o", "--replace_ota_keys"):
4368e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker      OPTIONS.replace_ota_keys = True
437ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker    elif o in ("-t", "--tag_changes"):
438ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker      new = []
439ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker      for i in a.split(","):
440ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker        i = i.strip()
441ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker        if not i or i[0] not in "-+":
442ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker          raise ValueError("Bad tag change '%s'" % (i,))
443ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker        new.append(i[0] + i[1:].strip())
444ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker      OPTIONS.tag_changes = tuple(new)
445f19b365cc9021104586d65385d246db06639fc46Geremy Condra    elif o == "--replace_verity_public_key":
446f19b365cc9021104586d65385d246db06639fc46Geremy Condra      OPTIONS.replace_verity_public_key = (True, a)
447f19b365cc9021104586d65385d246db06639fc46Geremy Condra    elif o == "--replace_verity_private_key":
448f19b365cc9021104586d65385d246db06639fc46Geremy Condra      OPTIONS.replace_verity_private_key = (True, a)
449eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    else:
450eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      return False
451eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    return True
452eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
453eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  args = common.ParseOptions(argv, __doc__,
45405d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker                             extra_opts="e:d:k:ot:",
45505d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker                             extra_long_opts=["extra_apks=",
456eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker                                              "default_key_mappings=",
4578e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker                                              "key_mapping=",
45817aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker                                              "replace_ota_keys",
459f19b365cc9021104586d65385d246db06639fc46Geremy Condra                                              "tag_changes=",
460f19b365cc9021104586d65385d246db06639fc46Geremy Condra                                              "replace_verity_public_key=",
461f19b365cc9021104586d65385d246db06639fc46Geremy Condra                                              "replace_verity_private_key="],
462eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker                             extra_option_handler=option_handler)
463eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
464eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  if len(args) != 2:
465eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    common.Usage(__doc__)
466eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    sys.exit(1)
467eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
468eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  input_zip = zipfile.ZipFile(args[0], "r")
469eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  output_zip = zipfile.ZipFile(args[1], "w")
470eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
471831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker  misc_info = common.LoadInfoDict(input_zip)
472831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker
473831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker  BuildKeyMap(misc_info, key_mapping_options)
474831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker
475eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker  apk_key_map = GetApkCerts(input_zip)
476eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker  CheckAllApksSigned(input_zip, apk_key_map)
477eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker
478eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker  key_passwords = common.GetKeyPasswords(set(apk_key_map.values()))
479412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker  ProcessTargetFiles(input_zip, output_zip, misc_info,
480412c02fffbeb137868945f6485b249cc4b49eaeaDoug Zongker                     apk_key_map, key_passwords)
4818e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker
482eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  input_zip.close()
483eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  output_zip.close()
484eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
4853c84f569487c4e59baa332be33b5430fdefb76b3Doug Zongker  add_img_to_target_files.AddImagesToTargetFiles(args[1])
4863c84f569487c4e59baa332be33b5430fdefb76b3Doug Zongker
487eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  print "done."
488eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
489eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
490eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerif __name__ == '__main__':
491eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  try:
492eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    main(sys.argv[1:])
493eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  except common.ExternalError, e:
494eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    print
495eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    print "   ERROR: %s" % (e,)
496eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    print
497eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    sys.exit(1)
498