sign_target_files_apks revision f6a53aa5f24878ad9098409ed3d3f41bb5c63fb5
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
39eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        build/target/product/security/testkey   ==>  $dir/releasekey
40eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        build/target/product/security/media     ==>  $dir/media
41eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        build/target/product/security/shared    ==>  $dir/shared
42eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        build/target/product/security/platform  ==>  $dir/platform
43eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
44eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      -d and -k options are added to the set of mappings in the order
45eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      in which they appear on the command line.
468e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker
478e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  -o  (--replace_ota_keys)
488e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker      Replace the certificate (public key) used by OTA package
498e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker      verification with the one specified in the input target_files
508e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker      zip (in the META/otakeys.txt file).  Key remapping (-k and -d)
518e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker      is performed on this key.
5217aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker
53ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker  -t  (--tag_changes)  <+tag>,<-tag>,...
54ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker      Comma-separated list of changes to make to the set of tags (in
55ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker      the last component of the build fingerprint).  Prefix each with
56ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker      '+' or '-' to indicate whether that tag should be added or
57ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker      removed.  Changes are processed in the order they appear.
585f5f08dd226a153ff4c73c0b1918bd5cc1afcffbDoug Zongker      Default value is "-test-keys,+release-keys".
59ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker
60eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker"""
61eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
62eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport sys
63eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
64eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerif sys.hexversion < 0x02040000:
65eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  print >> sys.stderr, "Python 2.4 or newer is required."
66eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  sys.exit(1)
67eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
688e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongkerimport cStringIO
698e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongkerimport copy
70eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport os
71eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport re
72eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport subprocess
73eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport tempfile
74eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport zipfile
75eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
76eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport common
77eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
78eef3944eb3673329b5e89cf188ac592805a0b08dDoug ZongkerOPTIONS = common.OPTIONS
79eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
80eef3944eb3673329b5e89cf188ac592805a0b08dDoug ZongkerOPTIONS.extra_apks = {}
81eef3944eb3673329b5e89cf188ac592805a0b08dDoug ZongkerOPTIONS.key_map = {}
828e931bf999693cac54c99deb1ef668d0e6164ecfDoug ZongkerOPTIONS.replace_ota_keys = False
835f5f08dd226a153ff4c73c0b1918bd5cc1afcffbDoug ZongkerOPTIONS.tag_changes = ("-test-keys", "+release-keys")
84eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
85eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerdef GetApkCerts(tf_zip):
86f6a53aa5f24878ad9098409ed3d3f41bb5c63fb5Doug Zongker  certmap = common.ReadApkCerts(tf_zip)
87f6a53aa5f24878ad9098409ed3d3f41bb5c63fb5Doug Zongker
88f6a53aa5f24878ad9098409ed3d3f41bb5c63fb5Doug Zongker  # apply the key remapping to the contents of the file
89f6a53aa5f24878ad9098409ed3d3f41bb5c63fb5Doug Zongker  for apk, cert in certmap.iteritems():
90f6a53aa5f24878ad9098409ed3d3f41bb5c63fb5Doug Zongker    certmap[apk] = OPTIONS.key_map.get(cert, cert)
91f6a53aa5f24878ad9098409ed3d3f41bb5c63fb5Doug Zongker
92f6a53aa5f24878ad9098409ed3d3f41bb5c63fb5Doug Zongker  # apply all the -e options, overriding anything in the file
93ad88c7ce4f3a65827d4cd5b5ed01324b3b368dd9Doug Zongker  for apk, cert in OPTIONS.extra_apks.iteritems():
94ad88c7ce4f3a65827d4cd5b5ed01324b3b368dd9Doug Zongker    certmap[apk] = OPTIONS.key_map.get(cert, cert)
95f6a53aa5f24878ad9098409ed3d3f41bb5c63fb5Doug Zongker
96eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  return certmap
97eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
98eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
99eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongkerdef CheckAllApksSigned(input_tf_zip, apk_key_map):
100eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker  """Check that all the APKs we want to sign have keys specified, and
101eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker  error out if they don't."""
102eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker  unknown_apks = []
103eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker  for info in input_tf_zip.infolist():
104eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker    if info.filename.endswith(".apk"):
105eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker      name = os.path.basename(info.filename)
106eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker      if name not in apk_key_map:
107eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker        unknown_apks.append(name)
108eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker  if unknown_apks:
109eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker    print "ERROR: no key specified for:\n\n ",
110eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker    print "\n  ".join(unknown_apks)
111eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker    print "\nUse '-e <apkname>=' to specify a key (which may be an"
112eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker    print "empty string to not sign this apk)."
113eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker    sys.exit(1)
114eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker
115eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker
116eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerdef SignApk(data, keyname, pw):
117eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  unsigned = tempfile.NamedTemporaryFile()
118eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  unsigned.write(data)
119eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  unsigned.flush()
120eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
121eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  signed = tempfile.NamedTemporaryFile()
122eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
123eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  common.SignFile(unsigned.name, signed.name, keyname, pw, align=4)
124eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
125eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  data = signed.read()
126eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  unsigned.close()
127eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  signed.close()
128eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
129eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  return data
130eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
131eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
132eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongkerdef SignApks(input_tf_zip, output_tf_zip, apk_key_map, key_passwords):
133eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  maxsize = max([len(os.path.basename(i.filename))
134eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker                 for i in input_tf_zip.infolist()
135eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker                 if i.filename.endswith('.apk')])
136eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
137eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  for info in input_tf_zip.infolist():
138eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    data = input_tf_zip.read(info.filename)
1398e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker    out_info = copy.copy(info)
140eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    if info.filename.endswith(".apk"):
141eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      name = os.path.basename(info.filename)
14243874f8c864972b9dae7e4927aa347455b774c94Doug Zongker      key = apk_key_map[name]
143f6a53aa5f24878ad9098409ed3d3f41bb5c63fb5Doug Zongker      if key not in common.SPECIAL_CERT_STRINGS:
14443874f8c864972b9dae7e4927aa347455b774c94Doug Zongker        print "    signing: %-*s (%s)" % (maxsize, name, key)
145eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        signed_data = SignApk(data, key, key_passwords[key])
1468e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker        output_tf_zip.writestr(out_info, signed_data)
147eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      else:
148eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        # an APK we're not supposed to sign.
14943874f8c864972b9dae7e4927aa347455b774c94Doug Zongker        print "NOT signing: %s" % (name,)
1508e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker        output_tf_zip.writestr(out_info, data)
1518e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker    elif info.filename in ("SYSTEM/build.prop",
1528e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker                           "RECOVERY/RAMDISK/default.prop"):
15317aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker      print "rewriting %s:" % (info.filename,)
15417aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker      new_data = RewriteProps(data)
15517aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker      output_tf_zip.writestr(out_info, new_data)
156eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    else:
157eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      # a non-APK file; copy it verbatim
1588e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker      output_tf_zip.writestr(out_info, data)
1598e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker
1608e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker
16117aa944001e7ae2425beec75d3ebc280413631eeDoug Zongkerdef RewriteProps(data):
16217aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker  output = []
16317aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker  for line in data.split("\n"):
16417aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker    line = line.strip()
16517aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker    original_line = line
16617aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker    if line and line[0] != '#':
16717aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker      key, value = line.split("=", 1)
16817aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker      if key == "ro.build.fingerprint":
16917aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker        pieces = line.split("/")
17017aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker        tags = set(pieces[-1].split(","))
171ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker        for ch in OPTIONS.tag_changes:
172ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker          if ch[0] == "-":
173ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker            tags.discard(ch[1:])
174ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker          elif ch[0] == "+":
175ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker            tags.add(ch[1:])
17617aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker        line = "/".join(pieces[:-1] + [",".join(sorted(tags))])
17717aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker      elif key == "ro.build.description":
17817aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker        pieces = line.split(" ")
17917aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker        assert len(pieces) == 5
18017aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker        tags = set(pieces[-1].split(","))
181ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker        for ch in OPTIONS.tag_changes:
182ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker          if ch[0] == "-":
183ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker            tags.discard(ch[1:])
184ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker          elif ch[0] == "+":
185ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker            tags.add(ch[1:])
18617aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker        line = " ".join(pieces[:-1] + [",".join(sorted(tags))])
18717aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker    if line != original_line:
18817aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker      print "  replace: ", original_line
18917aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker      print "     with: ", line
19017aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker    output.append(line)
19117aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker  return "\n".join(output) + "\n"
19217aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker
19317aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker
1948e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongkerdef ReplaceOtaKeys(input_tf_zip, output_tf_zip):
1958e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  try:
1968e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker    keylist = input_tf_zip.read("META/otakeys.txt").split()
1978e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  except KeyError:
1988e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker    raise ExternalError("can't read META/otakeys.txt from input")
1998e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker
2008e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  mapped_keys = []
2018e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  for k in keylist:
2028e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker    m = re.match(r"^(.*)\.x509\.pem$", k)
2038e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker    if not m:
2048e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker      raise ExternalError("can't parse \"%s\" from META/otakeys.txt" % (k,))
2058e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker    k = m.group(1)
2068e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker    mapped_keys.append(OPTIONS.key_map.get(k, k) + ".x509.pem")
2078e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker
208e05628cc8df4ec4b69befa9652d81eb81f0ab008Doug Zongker  if mapped_keys:
209e05628cc8df4ec4b69befa9652d81eb81f0ab008Doug Zongker    print "using:\n   ", "\n   ".join(mapped_keys)
210e05628cc8df4ec4b69befa9652d81eb81f0ab008Doug Zongker    print "for OTA package verification"
211e05628cc8df4ec4b69befa9652d81eb81f0ab008Doug Zongker  else:
212e05628cc8df4ec4b69befa9652d81eb81f0ab008Doug Zongker    mapped_keys.append(
213e05628cc8df4ec4b69befa9652d81eb81f0ab008Doug Zongker        OPTIONS.key_map["build/target/product/security/testkey"] + ".x509.pem")
214e05628cc8df4ec4b69befa9652d81eb81f0ab008Doug Zongker    print "META/otakeys.txt has no keys; using", mapped_keys[0]
2158e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker
2168e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  # recovery uses a version of the key that has been slightly
2178e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  # predigested (by DumpPublicKey.java) and put in res/keys.
2188e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker
219602a84e0bbf1807a9403cfa50184241f6fc035c4Doug Zongker  p = common.Run(["java", "-jar",
220602a84e0bbf1807a9403cfa50184241f6fc035c4Doug Zongker                  os.path.join(OPTIONS.search_path, "framework", "dumpkey.jar")]
221602a84e0bbf1807a9403cfa50184241f6fc035c4Doug Zongker                 + mapped_keys,
2228e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker                 stdout=subprocess.PIPE)
2238e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  data, _ = p.communicate()
2248e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  if p.returncode != 0:
2258e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker    raise ExternalError("failed to run dumpkeys")
226048e7ca15f6391681490ce564bc71194adf146aaDoug Zongker  common.ZipWriteStr(output_tf_zip, "RECOVERY/RAMDISK/res/keys", data)
2278e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker
2288e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  # SystemUpdateActivity uses the x509.pem version of the keys, but
2298e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  # put into a zipfile system/etc/security/otacerts.zip.
2308e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker
2318e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  tempfile = cStringIO.StringIO()
2328e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  certs_zip = zipfile.ZipFile(tempfile, "w")
2338e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  for k in mapped_keys:
2348e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker    certs_zip.write(k)
2358e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  certs_zip.close()
236048e7ca15f6391681490ce564bc71194adf146aaDoug Zongker  common.ZipWriteStr(output_tf_zip, "SYSTEM/etc/security/otacerts.zip",
237048e7ca15f6391681490ce564bc71194adf146aaDoug Zongker                     tempfile.getvalue())
238eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
239eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
240eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerdef main(argv):
241eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
242eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  def option_handler(o, a):
24305d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker    if o in ("-e", "--extra_apks"):
244eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      names, key = a.split("=")
245eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      names = names.split(",")
246eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      for n in names:
247eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        OPTIONS.extra_apks[n] = key
248eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    elif o in ("-d", "--default_key_mappings"):
249eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      OPTIONS.key_map.update({
250eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker          "build/target/product/security/testkey": "%s/releasekey" % (a,),
251eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker          "build/target/product/security/media": "%s/media" % (a,),
252eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker          "build/target/product/security/shared": "%s/shared" % (a,),
253eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker          "build/target/product/security/platform": "%s/platform" % (a,),
254eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker          })
255eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    elif o in ("-k", "--key_mapping"):
256eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      s, d = a.split("=")
257eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      OPTIONS.key_map[s] = d
2588e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker    elif o in ("-o", "--replace_ota_keys"):
2598e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker      OPTIONS.replace_ota_keys = True
260ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker    elif o in ("-t", "--tag_changes"):
261ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker      new = []
262ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker      for i in a.split(","):
263ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker        i = i.strip()
264ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker        if not i or i[0] not in "-+":
265ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker          raise ValueError("Bad tag change '%s'" % (i,))
266ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker        new.append(i[0] + i[1:].strip())
267ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker      OPTIONS.tag_changes = tuple(new)
268eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    else:
269eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      return False
270eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    return True
271eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
272eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  args = common.ParseOptions(argv, __doc__,
27305d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker                             extra_opts="e:d:k:ot:",
27405d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker                             extra_long_opts=["extra_apks=",
275eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker                                              "default_key_mappings=",
2768e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker                                              "key_mapping=",
27717aa944001e7ae2425beec75d3ebc280413631eeDoug Zongker                                              "replace_ota_keys",
278ae877013ab8d87b9f0da111adcb7621f477451c6Doug Zongker                                              "tag_changes="],
279eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker                             extra_option_handler=option_handler)
280eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
281eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  if len(args) != 2:
282eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    common.Usage(__doc__)
283eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    sys.exit(1)
284eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
285eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  input_zip = zipfile.ZipFile(args[0], "r")
286eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  output_zip = zipfile.ZipFile(args[1], "w")
287eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
288eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker  apk_key_map = GetApkCerts(input_zip)
289eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker  CheckAllApksSigned(input_zip, apk_key_map)
290eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker
291eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker  key_passwords = common.GetKeyPasswords(set(apk_key_map.values()))
292eb338efd2eae20962c7ca75baf161be540b3d664Doug Zongker  SignApks(input_zip, output_zip, apk_key_map, key_passwords)
293eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
2948e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker  if OPTIONS.replace_ota_keys:
2958e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker    ReplaceOtaKeys(input_zip, output_zip)
2968e931bf999693cac54c99deb1ef668d0e6164ecfDoug Zongker
297eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  input_zip.close()
298eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  output_zip.close()
299eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
300eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  print "done."
301eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
302eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
303eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerif __name__ == '__main__':
304eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  try:
305eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    main(sys.argv[1:])
306eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  except common.ExternalError, e:
307eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    print
308eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    print "   ERROR: %s" % (e,)
309eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    print
310eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    sys.exit(1)
311