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
70eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerif sys.hexversion < 0x02040000:
71eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  print >> sys.stderr, "Python 2.4 or newer is required."
72eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  sys.exit(1)
73eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
748e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongkerimport cStringIO
758e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongkerimport copy
76eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport os
77eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport re
78eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport subprocess
79eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport tempfile
80eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport zipfile
81eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
82eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport common
83eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
84eef3944eb3673329b5e89cf188ac592805a0b08dDoug ZongkerOPTIONS = common.OPTIONS
85eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
86eef3944eb3673329b5e89cf188ac592805a0b08dDoug ZongkerOPTIONS.extra_apks = {}
87eef3944eb3673329b5e89cf188ac592805a0b08dDoug ZongkerOPTIONS.key_map = {}
888e931bf999693cac54c99deb1ef668d0e6164ecfDoug ZongkerOPTIONS.replace_ota_keys = False
89831840e51b0403671f746ebc32090b7d6e548c08Doug ZongkerOPTIONS.tag_changes = ("-test-keys", "-dev-keys", "+release-keys")
90eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
91eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerdef GetApkCerts(tf_zip):
92f6a53aa5f24878ad9098409ed3d3f41bb5c63fb5Doug Zongker  certmap = common.ReadApkCerts(tf_zip)
93f6a53aa5f24878ad9098409ed3d3f41bb5c63fb5Doug Zongker
94f6a53aa5f24878ad9098409ed3d3f41bb5c63fb5Doug Zongker  # apply the key remapping to the contents of the file
95f6a53aa5f24878ad9098409ed3d3f41bb5c63fb5Doug Zongker  for apk, cert in certmap.iteritems():
96f6a53aa5f24878ad9098409ed3d3f41bb5c63fb5Doug Zongker    certmap[apk] = OPTIONS.key_map.get(cert, cert)
97f6a53aa5f24878ad9098409ed3d3f41bb5c63fb5Doug Zongker
98f6a53aa5f24878ad9098409ed3d3f41bb5c63fb5Doug Zongker  # apply all the -e options, overriding anything in the file
99ad88c7ce4f3a65827d4cd5b5ed01324b3b368dd9Doug Zongker  for apk, cert in OPTIONS.extra_apks.iteritems():
100decf995c5956e6f64f858d1c4e51a3f3b9829a51Doug Zongker    if not cert:
101decf995c5956e6f64f858d1c4e51a3f3b9829a51Doug Zongker      cert = "PRESIGNED"
102ad88c7ce4f3a65827d4cd5b5ed01324b3b368dd9Doug Zongker    certmap[apk] = OPTIONS.key_map.get(cert, cert)
103f6a53aa5f24878ad9098409ed3d3f41bb5c63fb5Doug Zongker
104eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  return certmap
105eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
106eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
107eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongkerdef CheckAllApksSigned(input_tf_zip, apk_key_map):
108eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker  """Check that all the APKs we want to sign have keys specified, and
109eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker  error out if they don't."""
110eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker  unknown_apks = []
111eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker  for info in input_tf_zip.infolist():
112eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker    if info.filename.endswith(".apk"):
113eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker      name = os.path.basename(info.filename)
114eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker      if name not in apk_key_map:
115eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker        unknown_apks.append(name)
116eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker  if unknown_apks:
117eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker    print "ERROR: no key specified for:\n\n ",
118eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker    print "\n  ".join(unknown_apks)
119eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker    print "\nUse '-e <apkname>=' to specify a key (which may be an"
120eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker    print "empty string to not sign this apk)."
121eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker    sys.exit(1)
122eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker
123eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker
124eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerdef SignApk(data, keyname, pw):
125eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  unsigned = tempfile.NamedTemporaryFile()
126eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  unsigned.write(data)
127eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  unsigned.flush()
128eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
129eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  signed = tempfile.NamedTemporaryFile()
130eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
131eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  common.SignFile(unsigned.name, signed.name, keyname, pw, align=4)
132eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
133eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  data = signed.read()
134eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  unsigned.close()
135eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  signed.close()
136eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
137eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  return data
138eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
139eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
140eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongkerdef SignApks(input_tf_zip, output_tf_zip, apk_key_map, key_passwords):
141eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  maxsize = max([len(os.path.basename(i.filename))
142eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker                 for i in input_tf_zip.infolist()
143eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker                 if i.filename.endswith('.apk')])
144eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
145eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  for info in input_tf_zip.infolist():
146eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    data = input_tf_zip.read(info.filename)
1478e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker    out_info = copy.copy(info)
148eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    if info.filename.endswith(".apk"):
149eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      name = os.path.basename(info.filename)
15043874f8c864972b9dae7e4927aa347455b774c94Doug Zongker      key = apk_key_map[name]
151f6a53aa5f24878ad9098409ed3d3f41bb5c63fb5Doug Zongker      if key not in common.SPECIAL_CERT_STRINGS:
15243874f8c864972b9dae7e4927aa347455b774c94Doug Zongker        print "    signing: %-*s (%s)" % (maxsize, name, key)
153eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        signed_data = SignApk(data, key, key_passwords[key])
1548e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker        output_tf_zip.writestr(out_info, signed_data)
155eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      else:
156eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        # an APK we're not supposed to sign.
15743874f8c864972b9dae7e4927aa347455b774c94Doug Zongker        print "NOT signing: %s" % (name,)
1588e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker        output_tf_zip.writestr(out_info, data)
1598e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker    elif info.filename in ("SYSTEM/build.prop",
1608e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker                           "RECOVERY/RAMDISK/default.prop"):
16117aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker      print "rewriting %s:" % (info.filename,)
16217aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker      new_data = RewriteProps(data)
16317aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker      output_tf_zip.writestr(out_info, new_data)
164eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    else:
165eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      # a non-APK file; copy it verbatim
1668e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker      output_tf_zip.writestr(out_info, data)
1678e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker
1688e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker
169c09abc8103a4c029cc2c6d59226a2a74be57d082Doug Zongkerdef EditTags(tags):
170c09abc8103a4c029cc2c6d59226a2a74be57d082Doug Zongker  """Given a string containing comma-separated tags, apply the edits
171c09abc8103a4c029cc2c6d59226a2a74be57d082Doug Zongker  specified in OPTIONS.tag_changes and return the updated string."""
172c09abc8103a4c029cc2c6d59226a2a74be57d082Doug Zongker  tags = set(tags.split(","))
173c09abc8103a4c029cc2c6d59226a2a74be57d082Doug Zongker  for ch in OPTIONS.tag_changes:
174c09abc8103a4c029cc2c6d59226a2a74be57d082Doug Zongker    if ch[0] == "-":
175c09abc8103a4c029cc2c6d59226a2a74be57d082Doug Zongker      tags.discard(ch[1:])
176c09abc8103a4c029cc2c6d59226a2a74be57d082Doug Zongker    elif ch[0] == "+":
177c09abc8103a4c029cc2c6d59226a2a74be57d082Doug Zongker      tags.add(ch[1:])
178c09abc8103a4c029cc2c6d59226a2a74be57d082Doug Zongker  return ",".join(sorted(tags))
179c09abc8103a4c029cc2c6d59226a2a74be57d082Doug Zongker
180c09abc8103a4c029cc2c6d59226a2a74be57d082Doug Zongker
18117aa944001e7ae2425beec75d3ebc280413631eeDoug Zongkerdef RewriteProps(data):
18217aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker  output = []
18317aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker  for line in data.split("\n"):
18417aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker    line = line.strip()
18517aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker    original_line = line
18617aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker    if line and line[0] != '#':
18717aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker      key, value = line.split("=", 1)
18817aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker      if key == "ro.build.fingerprint":
189c09abc8103a4c029cc2c6d59226a2a74be57d082Doug Zongker        pieces = value.split("/")
190c09abc8103a4c029cc2c6d59226a2a74be57d082Doug Zongker        pieces[-1] = EditTags(pieces[-1])
191c09abc8103a4c029cc2c6d59226a2a74be57d082Doug Zongker        value = "/".join(pieces)
19217aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker      elif key == "ro.build.description":
193c09abc8103a4c029cc2c6d59226a2a74be57d082Doug Zongker        pieces = value.split(" ")
19417aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker        assert len(pieces) == 5
195c09abc8103a4c029cc2c6d59226a2a74be57d082Doug Zongker        pieces[-1] = EditTags(pieces[-1])
196c09abc8103a4c029cc2c6d59226a2a74be57d082Doug Zongker        value = " ".join(pieces)
197c09abc8103a4c029cc2c6d59226a2a74be57d082Doug Zongker      elif key == "ro.build.tags":
198c09abc8103a4c029cc2c6d59226a2a74be57d082Doug Zongker        value = EditTags(value)
199a8608a7f7cee388192780f8988b5dc5966423eefDoug Zongker      elif key == "ro.build.display.id":
200a8608a7f7cee388192780f8988b5dc5966423eefDoug Zongker        # change, eg, "JWR66N dev-keys" to "JWR66N"
201a8608a7f7cee388192780f8988b5dc5966423eefDoug Zongker        value = value.split()
202a8608a7f7cee388192780f8988b5dc5966423eefDoug Zongker        if len(value) == 2 and value[1].endswith("-keys"):
203a8608a7f7cee388192780f8988b5dc5966423eefDoug Zongker          value = value[0]
204c09abc8103a4c029cc2c6d59226a2a74be57d082Doug Zongker      line = key + "=" + value
20517aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker    if line != original_line:
20617aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker      print "  replace: ", original_line
20717aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker      print "     with: ", line
20817aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker    output.append(line)
20917aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker  return "\n".join(output) + "\n"
21017aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker
21117aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker
212831840e51b0403671f746ebc32090b7d6e548c08Doug Zongkerdef ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info):
2138e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  try:
2148e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker    keylist = input_tf_zip.read("META/otakeys.txt").split()
2158e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  except KeyError:
216a28acc6972ce35e9dfab061f175e229859d3e4dbT.R. Fullhart    raise common.ExternalError("can't read META/otakeys.txt from input")
2178e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker
218e121d6acf47c3056e079ff62c82171e889cec3e0Doug Zongker  extra_recovery_keys = misc_info.get("extra_recovery_keys", None)
219e121d6acf47c3056e079ff62c82171e889cec3e0Doug Zongker  if extra_recovery_keys:
220e121d6acf47c3056e079ff62c82171e889cec3e0Doug Zongker    extra_recovery_keys = [OPTIONS.key_map.get(k, k) + ".x509.pem"
221e121d6acf47c3056e079ff62c82171e889cec3e0Doug Zongker                           for k in extra_recovery_keys.split()]
222e121d6acf47c3056e079ff62c82171e889cec3e0Doug Zongker    if extra_recovery_keys:
223e121d6acf47c3056e079ff62c82171e889cec3e0Doug Zongker      print "extra recovery-only key(s): " + ", ".join(extra_recovery_keys)
224e121d6acf47c3056e079ff62c82171e889cec3e0Doug Zongker  else:
225e121d6acf47c3056e079ff62c82171e889cec3e0Doug Zongker    extra_recovery_keys = []
226e121d6acf47c3056e079ff62c82171e889cec3e0Doug Zongker
2278e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  mapped_keys = []
2288e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  for k in keylist:
2298e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker    m = re.match(r"^(.*)\.x509\.pem$", k)
2308e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker    if not m:
231a28acc6972ce35e9dfab061f175e229859d3e4dbT.R. Fullhart      raise common.ExternalError("can't parse \"%s\" from META/otakeys.txt" % (k,))
2328e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker    k = m.group(1)
2338e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker    mapped_keys.append(OPTIONS.key_map.get(k, k) + ".x509.pem")
2348e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker
235e05628cc8df4ec4b69befa9652d81eb81f0ab008Doug Zongker  if mapped_keys:
236e05628cc8df4ec4b69befa9652d81eb81f0ab008Doug Zongker    print "using:\n   ", "\n   ".join(mapped_keys)
237e05628cc8df4ec4b69befa9652d81eb81f0ab008Doug Zongker    print "for OTA package verification"
238e05628cc8df4ec4b69befa9652d81eb81f0ab008Doug Zongker  else:
239831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker    devkey = misc_info.get("default_system_dev_certificate",
240831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker                           "build/target/product/security/testkey")
241e05628cc8df4ec4b69befa9652d81eb81f0ab008Doug Zongker    mapped_keys.append(
242831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker        OPTIONS.key_map.get(devkey, devkey) + ".x509.pem")
243e05628cc8df4ec4b69befa9652d81eb81f0ab008Doug Zongker    print "META/otakeys.txt has no keys; using", mapped_keys[0]
2448e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker
2458e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  # recovery uses a version of the key that has been slightly
2468e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  # predigested (by DumpPublicKey.java) and put in res/keys.
247e121d6acf47c3056e079ff62c82171e889cec3e0Doug Zongker  # extra_recovery_keys are used only in recovery.
2488e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker
249602a84e0bbf1807a9403cfa50184241f6fc035c4Doug Zongker  p = common.Run(["java", "-jar",
250602a84e0bbf1807a9403cfa50184241f6fc035c4Doug Zongker                  os.path.join(OPTIONS.search_path, "framework", "dumpkey.jar")]
251e121d6acf47c3056e079ff62c82171e889cec3e0Doug Zongker                 + mapped_keys + extra_recovery_keys,
2528e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker                 stdout=subprocess.PIPE)
2538e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  data, _ = p.communicate()
2548e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  if p.returncode != 0:
255a28acc6972ce35e9dfab061f175e229859d3e4dbT.R. Fullhart    raise common.ExternalError("failed to run dumpkeys")
256048e7ca15f6391681490ce564bc71194adf146aaDoug Zongker  common.ZipWriteStr(output_tf_zip, "RECOVERY/RAMDISK/res/keys", data)
2578e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker
2588e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  # SystemUpdateActivity uses the x509.pem version of the keys, but
2598e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  # put into a zipfile system/etc/security/otacerts.zip.
260e121d6acf47c3056e079ff62c82171e889cec3e0Doug Zongker  # We DO NOT include the extra_recovery_keys (if any) here.
2618e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker
2628e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  tempfile = cStringIO.StringIO()
2638e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  certs_zip = zipfile.ZipFile(tempfile, "w")
2648e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  for k in mapped_keys:
2658e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker    certs_zip.write(k)
2668e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  certs_zip.close()
267048e7ca15f6391681490ce564bc71194adf146aaDoug Zongker  common.ZipWriteStr(output_tf_zip, "SYSTEM/etc/security/otacerts.zip",
268048e7ca15f6391681490ce564bc71194adf146aaDoug Zongker                     tempfile.getvalue())
269eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
270eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
271831840e51b0403671f746ebc32090b7d6e548c08Doug Zongkerdef BuildKeyMap(misc_info, key_mapping_options):
272831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker  for s, d in key_mapping_options:
273831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker    if s is None:   # -d option
274831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker      devkey = misc_info.get("default_system_dev_certificate",
275831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker                             "build/target/product/security/testkey")
276831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker      devkeydir = os.path.dirname(devkey)
277831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker
278831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker      OPTIONS.key_map.update({
279831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker          devkeydir + "/testkey":  d + "/releasekey",
280831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker          devkeydir + "/devkey":   d + "/releasekey",
281831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker          devkeydir + "/media":    d + "/media",
282831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker          devkeydir + "/shared":   d + "/shared",
283831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker          devkeydir + "/platform": d + "/platform",
284831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker          })
285831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker    else:
286831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker      OPTIONS.key_map[s] = d
287831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker
288831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker
289eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerdef main(argv):
290eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
291831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker  key_mapping_options = []
292831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker
293eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  def option_handler(o, a):
29405d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker    if o in ("-e", "--extra_apks"):
295eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      names, key = a.split("=")
296eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      names = names.split(",")
297eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      for n in names:
298eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        OPTIONS.extra_apks[n] = key
299eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    elif o in ("-d", "--default_key_mappings"):
300831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker      key_mapping_options.append((None, a))
301eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    elif o in ("-k", "--key_mapping"):
302831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker      key_mapping_options.append(a.split("=", 1))
3038e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker    elif o in ("-o", "--replace_ota_keys"):
3048e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker      OPTIONS.replace_ota_keys = True
305ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker    elif o in ("-t", "--tag_changes"):
306ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker      new = []
307ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker      for i in a.split(","):
308ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker        i = i.strip()
309ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker        if not i or i[0] not in "-+":
310ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker          raise ValueError("Bad tag change '%s'" % (i,))
311ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker        new.append(i[0] + i[1:].strip())
312ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker      OPTIONS.tag_changes = tuple(new)
313eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    else:
314eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      return False
315eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    return True
316eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
317eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  args = common.ParseOptions(argv, __doc__,
31805d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker                             extra_opts="e:d:k:ot:",
31905d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker                             extra_long_opts=["extra_apks=",
320eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker                                              "default_key_mappings=",
3218e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker                                              "key_mapping=",
32217aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker                                              "replace_ota_keys",
323ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker                                              "tag_changes="],
324eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker                             extra_option_handler=option_handler)
325eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
326eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  if len(args) != 2:
327eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    common.Usage(__doc__)
328eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    sys.exit(1)
329eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
330eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  input_zip = zipfile.ZipFile(args[0], "r")
331eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  output_zip = zipfile.ZipFile(args[1], "w")
332eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
333831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker  misc_info = common.LoadInfoDict(input_zip)
334831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker
335831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker  BuildKeyMap(misc_info, key_mapping_options)
336831840e51b0403671f746ebc32090b7d6e548c08Doug Zongker
337eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker  apk_key_map = GetApkCerts(input_zip)
338eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker  CheckAllApksSigned(input_zip, apk_key_map)
339eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker
340eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker  key_passwords = common.GetKeyPasswords(set(apk_key_map.values()))
341eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker  SignApks(input_zip, output_zip, apk_key_map, key_passwords)
342eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
3438e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  if OPTIONS.replace_ota_keys:
344b11e2d78ecc3eac29b259bc10a466d65d50ac653Doug Zongker    ReplaceOtaKeys(input_zip, output_zip, misc_info)
3458e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker
346eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  input_zip.close()
347eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  output_zip.close()
348eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
349eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  print "done."
350eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
351eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
352eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerif __name__ == '__main__':
353eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  try:
354eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    main(sys.argv[1:])
355eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  except common.ExternalError, e:
356eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    print
357eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    print "   ERROR: %s" % (e,)
358eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    print
359eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    sys.exit(1)
360