Merge change If6a53aa5
* changes: add "EXTERNAL" as special value of LOCAL_CERTIFICATE
This commit is contained in:
commit
5125e441b1
|
@ -208,8 +208,11 @@ $(APKCERTS_FILE): $(all_built_packages)
|
||||||
@mkdir -p $(dir $@)
|
@mkdir -p $(dir $@)
|
||||||
@rm -f $@
|
@rm -f $@
|
||||||
$(hide) $(foreach p,$(PACKAGES),\
|
$(hide) $(foreach p,$(PACKAGES),\
|
||||||
|
$(if $(PACKAGES.$(p).EXTERNAL_KEY),\
|
||||||
|
echo 'name="$(p).apk" certificate="EXTERNAL" \
|
||||||
|
private_key=""' >> $@;,\
|
||||||
echo 'name="$(p).apk" certificate="$(PACKAGES.$(p).CERTIFICATE)" \
|
echo 'name="$(p).apk" certificate="$(PACKAGES.$(p).CERTIFICATE)" \
|
||||||
private_key="$(PACKAGES.$(p).PRIVATE_KEY)"' >> $@;)
|
private_key="$(PACKAGES.$(p).PRIVATE_KEY)"' >> $@;))
|
||||||
|
|
||||||
.PHONY: apkcerts-list
|
.PHONY: apkcerts-list
|
||||||
apkcerts-list: $(APKCERTS_FILE)
|
apkcerts-list: $(APKCERTS_FILE)
|
||||||
|
|
|
@ -244,6 +244,15 @@ jni_shared_libraries := \
|
||||||
ifeq ($(LOCAL_CERTIFICATE),)
|
ifeq ($(LOCAL_CERTIFICATE),)
|
||||||
LOCAL_CERTIFICATE := testkey
|
LOCAL_CERTIFICATE := testkey
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(LOCAL_CERTIFICATE),EXTERNAL)
|
||||||
|
# The special value "EXTERNAL" means that we will sign it with the
|
||||||
|
# default testkey, apply predexopt, but then expect the final .apk
|
||||||
|
# (after dexopting) to be signed by an outside tool.
|
||||||
|
LOCAL_CERTIFICATE := testkey
|
||||||
|
PACKAGES.$(LOCAL_PACKAGE_NAME).EXTERNAL_KEY := 1
|
||||||
|
endif
|
||||||
|
|
||||||
# If this is not an absolute certificate, assign it to a generic one.
|
# If this is not an absolute certificate, assign it to a generic one.
|
||||||
ifeq ($(dir $(strip $(LOCAL_CERTIFICATE))),./)
|
ifeq ($(dir $(strip $(LOCAL_CERTIFICATE))),./)
|
||||||
LOCAL_CERTIFICATE := $(SRC_TARGET_DIR)/product/security/$(LOCAL_CERTIFICATE)
|
LOCAL_CERTIFICATE := $(SRC_TARGET_DIR)/product/security/$(LOCAL_CERTIFICATE)
|
||||||
|
|
|
@ -42,6 +42,16 @@ $(LOCAL_BUILT_MODULE) : $(LOCAL_PATH)/$(LOCAL_SRC_FILES) | $(ACP)
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(LOCAL_CERTIFICATE),EXTERNAL)
|
||||||
|
# The magic string "EXTERNAL" means this package will be signed with
|
||||||
|
# the test key throughout the build process, but we expect the final
|
||||||
|
# package to be signed with a different key.
|
||||||
|
#
|
||||||
|
# This can be used for packages where we don't have access to the
|
||||||
|
# keys, but want the package to be predexopt'ed.
|
||||||
|
LOCAL_CERTIFICATE := testkey
|
||||||
|
PACKAGES.$(LOCAL_MODULE).EXTERNAL_KEY := 1
|
||||||
|
endif
|
||||||
ifeq ($(LOCAL_CERTIFICATE),)
|
ifeq ($(LOCAL_CERTIFICATE),)
|
||||||
ifneq ($(filter APPS,$(LOCAL_MODULE_CLASS)),)
|
ifneq ($(filter APPS,$(LOCAL_MODULE_CLASS)),)
|
||||||
# It is now a build error to add a prebuilt .apk without
|
# It is now a build error to add a prebuilt .apk without
|
||||||
|
|
|
@ -248,6 +248,7 @@ class TargetFiles(object):
|
||||||
d = common.UnzipTemp(filename, '*.apk')
|
d = common.UnzipTemp(filename, '*.apk')
|
||||||
try:
|
try:
|
||||||
self.apks = {}
|
self.apks = {}
|
||||||
|
self.apks_by_basename = {}
|
||||||
for dirpath, dirnames, filenames in os.walk(d):
|
for dirpath, dirnames, filenames in os.walk(d):
|
||||||
for fn in filenames:
|
for fn in filenames:
|
||||||
if fn.endswith(".apk"):
|
if fn.endswith(".apk"):
|
||||||
|
@ -255,12 +256,17 @@ class TargetFiles(object):
|
||||||
displayname = fullname[len(d)+1:]
|
displayname = fullname[len(d)+1:]
|
||||||
apk = APK(fullname, displayname)
|
apk = APK(fullname, displayname)
|
||||||
self.apks[apk.package] = apk
|
self.apks[apk.package] = apk
|
||||||
|
self.apks_by_basename[os.path.basename(apk.filename)] = apk
|
||||||
|
|
||||||
self.max_pkg_len = max(self.max_pkg_len, len(apk.package))
|
self.max_pkg_len = max(self.max_pkg_len, len(apk.package))
|
||||||
self.max_fn_len = max(self.max_fn_len, len(apk.filename))
|
self.max_fn_len = max(self.max_fn_len, len(apk.filename))
|
||||||
finally:
|
finally:
|
||||||
shutil.rmtree(d)
|
shutil.rmtree(d)
|
||||||
|
|
||||||
|
z = zipfile.ZipFile(open(filename, "rb"))
|
||||||
|
self.certmap = common.ReadApkCerts(z)
|
||||||
|
z.close()
|
||||||
|
|
||||||
def CheckSharedUids(self):
|
def CheckSharedUids(self):
|
||||||
"""Look for any instances where packages signed with different
|
"""Look for any instances where packages signed with different
|
||||||
certs request the same sharedUserId."""
|
certs request the same sharedUserId."""
|
||||||
|
@ -292,6 +298,20 @@ class TargetFiles(object):
|
||||||
apk.package, apk.filename)
|
apk.package, apk.filename)
|
||||||
print
|
print
|
||||||
|
|
||||||
|
def CheckExternalSignatures(self):
|
||||||
|
for apk_filename, certname in self.certmap.iteritems():
|
||||||
|
if certname == "EXTERNAL":
|
||||||
|
# Apps marked EXTERNAL should be signed with the test key
|
||||||
|
# during development, then manually re-signed after
|
||||||
|
# predexopting. Consider it an error if this app is now
|
||||||
|
# signed with any key that is present in our tree.
|
||||||
|
apk = self.apks_by_basename[apk_filename]
|
||||||
|
name = ALL_CERTS.Get(apk.cert)
|
||||||
|
if not name.startswith("unknown "):
|
||||||
|
Push(apk.filename)
|
||||||
|
AddProblem("hasn't been signed with EXTERNAL cert")
|
||||||
|
Pop()
|
||||||
|
|
||||||
def PrintCerts(self):
|
def PrintCerts(self):
|
||||||
"""Display a table of packages grouped by cert."""
|
"""Display a table of packages grouped by cert."""
|
||||||
by_cert = {}
|
by_cert = {}
|
||||||
|
@ -402,6 +422,7 @@ def main(argv):
|
||||||
Banner("target files")
|
Banner("target files")
|
||||||
target_files.PrintCerts()
|
target_files.PrintCerts()
|
||||||
target_files.CheckSharedUids()
|
target_files.CheckSharedUids()
|
||||||
|
target_files.CheckExternalSignatures()
|
||||||
if compare_files:
|
if compare_files:
|
||||||
if OPTIONS.text:
|
if OPTIONS.text:
|
||||||
Banner("comparison files")
|
Banner("comparison files")
|
||||||
|
|
|
@ -37,6 +37,11 @@ OPTIONS.tempfiles = []
|
||||||
OPTIONS.device_specific = None
|
OPTIONS.device_specific = None
|
||||||
OPTIONS.extras = {}
|
OPTIONS.extras = {}
|
||||||
|
|
||||||
|
|
||||||
|
# Values for "certificate" in apkcerts that mean special things.
|
||||||
|
SPECIAL_CERT_STRINGS = ("PRESIGNED", "EXTERNAL")
|
||||||
|
|
||||||
|
|
||||||
class ExternalError(RuntimeError): pass
|
class ExternalError(RuntimeError): pass
|
||||||
|
|
||||||
|
|
||||||
|
@ -166,9 +171,8 @@ def GetKeyPasswords(keylist):
|
||||||
need_passwords = []
|
need_passwords = []
|
||||||
devnull = open("/dev/null", "w+b")
|
devnull = open("/dev/null", "w+b")
|
||||||
for k in sorted(keylist):
|
for k in sorted(keylist):
|
||||||
# An empty-string key is used to mean don't re-sign this package.
|
# We don't need a password for things that aren't really keys.
|
||||||
# Obviously we don't need a password for this non-key.
|
if k in SPECIAL_CERT_STRINGS:
|
||||||
if not k:
|
|
||||||
no_passwords.append(k)
|
no_passwords.append(k)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -254,6 +258,28 @@ def CheckSize(data, target):
|
||||||
print " ", msg
|
print " ", msg
|
||||||
|
|
||||||
|
|
||||||
|
def ReadApkCerts(tf_zip):
|
||||||
|
"""Given a target_files ZipFile, parse the META/apkcerts.txt file
|
||||||
|
and return a {package: cert} dict."""
|
||||||
|
certmap = {}
|
||||||
|
for line in tf_zip.read("META/apkcerts.txt").split("\n"):
|
||||||
|
line = line.strip()
|
||||||
|
if not line: continue
|
||||||
|
m = re.match(r'^name="(.*)"\s+certificate="(.*)"\s+'
|
||||||
|
r'private_key="(.*)"$', line)
|
||||||
|
if m:
|
||||||
|
name, cert, privkey = m.groups()
|
||||||
|
if cert in SPECIAL_CERT_STRINGS and not privkey:
|
||||||
|
certmap[name] = cert
|
||||||
|
elif (cert.endswith(".x509.pem") and
|
||||||
|
privkey.endswith(".pk8") and
|
||||||
|
cert[:-9] == privkey[:-4]):
|
||||||
|
certmap[name] = cert[:-9]
|
||||||
|
else:
|
||||||
|
raise ValueError("failed to parse line from apkcerts.txt:\n" + line)
|
||||||
|
return certmap
|
||||||
|
|
||||||
|
|
||||||
COMMON_DOCSTRING = """
|
COMMON_DOCSTRING = """
|
||||||
-p (--path) <dir>
|
-p (--path) <dir>
|
||||||
Prepend <dir>/bin to the list of places to search for binaries
|
Prepend <dir>/bin to the list of places to search for binaries
|
||||||
|
|
|
@ -83,23 +83,16 @@ OPTIONS.replace_ota_keys = False
|
||||||
OPTIONS.tag_changes = ("-test-keys", "+release-keys")
|
OPTIONS.tag_changes = ("-test-keys", "+release-keys")
|
||||||
|
|
||||||
def GetApkCerts(tf_zip):
|
def GetApkCerts(tf_zip):
|
||||||
certmap = {}
|
certmap = common.ReadApkCerts(tf_zip)
|
||||||
for line in tf_zip.read("META/apkcerts.txt").split("\n"):
|
|
||||||
line = line.strip()
|
# apply the key remapping to the contents of the file
|
||||||
if not line: continue
|
for apk, cert in certmap.iteritems():
|
||||||
m = re.match(r'^name="(.*)"\s+certificate="(.*)\.x509\.pem"\s+'
|
certmap[apk] = OPTIONS.key_map.get(cert, cert)
|
||||||
r'private_key="\2\.pk8"$', line)
|
|
||||||
if m:
|
# apply all the -e options, overriding anything in the file
|
||||||
certmap[m.group(1)] = OPTIONS.key_map.get(m.group(2), m.group(2))
|
|
||||||
else:
|
|
||||||
m = re.match(r'^name="(.*)"\s+certificate="PRESIGNED"\s+'
|
|
||||||
r'private_key=""$', line)
|
|
||||||
if m:
|
|
||||||
certmap[m.group(1)] = None
|
|
||||||
else:
|
|
||||||
raise ValueError("failed to parse line from apkcerts.txt:\n" + line)
|
|
||||||
for apk, cert in OPTIONS.extra_apks.iteritems():
|
for apk, cert in OPTIONS.extra_apks.iteritems():
|
||||||
certmap[apk] = OPTIONS.key_map.get(cert, cert)
|
certmap[apk] = OPTIONS.key_map.get(cert, cert)
|
||||||
|
|
||||||
return certmap
|
return certmap
|
||||||
|
|
||||||
|
|
||||||
|
@ -147,7 +140,7 @@ def SignApks(input_tf_zip, output_tf_zip, apk_key_map, key_passwords):
|
||||||
if info.filename.endswith(".apk"):
|
if info.filename.endswith(".apk"):
|
||||||
name = os.path.basename(info.filename)
|
name = os.path.basename(info.filename)
|
||||||
key = apk_key_map[name]
|
key = apk_key_map[name]
|
||||||
if key:
|
if key not in common.SPECIAL_CERT_STRINGS:
|
||||||
print " signing: %-*s (%s)" % (maxsize, name, key)
|
print " signing: %-*s (%s)" % (maxsize, name, key)
|
||||||
signed_data = SignApk(data, key, key_passwords[key])
|
signed_data = SignApk(data, key, key_passwords[key])
|
||||||
output_tf_zip.writestr(out_info, signed_data)
|
output_tf_zip.writestr(out_info, signed_data)
|
||||||
|
|
Loading…
Reference in New Issue