Support custom APEX signing tool

When an APEX specifies its custom signing tool (custom_sign_tool:),
apexkeys.txt contains the info and sign_target_files_apks pass the value
to apex_util.

For now the Virt APEX has its own custom signing tool (sign_virt_apex),
which is added to OTATOOLS.

Bug: 193504286
Test: sign_target_files_apks invokes sign_virt_apex
Change-Id: Iba845723fe3e18f542963324b9c58cd00914c5ba
This commit is contained in:
Jooyung Han
2021-10-27 03:58:09 +09:00
parent 0f5a41da56
commit 8caba5e14e
5 changed files with 39 additions and 33 deletions

View File

@@ -4323,6 +4323,7 @@ INTERNAL_OTATOOLS_MODULES := \
shflags \ shflags \
sign_apex \ sign_apex \
sign_target_files_apks \ sign_target_files_apks \
sign_virt_apex \
signapk \ signapk \
simg2img \ simg2img \
sload_f2fs \ sload_f2fs \

View File

@@ -142,6 +142,7 @@ class ApexApkSigner(object):
has_signed_content = True has_signed_content = True
if self.sign_tool: if self.sign_tool:
logger.info('Signing payload contents in apex %s with %s', self.apex_path, self.sign_tool)
cmd = [self.sign_tool, '--avbtool', self.avbtool, payload_key, payload_dir] cmd = [self.sign_tool, '--avbtool', self.avbtool, payload_key, payload_dir]
common.RunAndCheckOutput(cmd) common.RunAndCheckOutput(cmd)
has_signed_content = True has_signed_content = True

View File

@@ -2107,7 +2107,7 @@ def GetKeyPasswords(keylist):
devnull = open("/dev/null", "w+b") devnull = open("/dev/null", "w+b")
for k in sorted(keylist): for k in sorted(keylist):
# We don't need a password for things that aren't really keys. # We don't need a password for things that aren't really keys.
if k in SPECIAL_CERT_STRINGS: if k in SPECIAL_CERT_STRINGS or k is None:
no_passwords.append(k) no_passwords.append(k)
continue continue

View File

@@ -262,7 +262,7 @@ def GetApexKeys(keys_info, key_map):
Args: Args:
keys_info: A dict that maps from APEX filenames to a tuple of (payload_key, keys_info: A dict that maps from APEX filenames to a tuple of (payload_key,
container_key). container_key, sign_tool).
key_map: A dict that overrides the keys, specified via command-line input. key_map: A dict that overrides the keys, specified via command-line input.
Returns: Returns:
@@ -280,11 +280,11 @@ def GetApexKeys(keys_info, key_map):
if apex not in keys_info: if apex not in keys_info:
logger.warning('Failed to find %s in target_files; Ignored', apex) logger.warning('Failed to find %s in target_files; Ignored', apex)
continue continue
keys_info[apex] = (key, keys_info[apex][1]) keys_info[apex] = (key, keys_info[apex][1], keys_info[apex][2])
# Apply the key remapping to container keys. # Apply the key remapping to container keys.
for apex, (payload_key, container_key) in keys_info.items(): for apex, (payload_key, container_key, sign_tool) in keys_info.items():
keys_info[apex] = (payload_key, key_map.get(container_key, container_key)) keys_info[apex] = (payload_key, key_map.get(container_key, container_key), sign_tool)
# Apply all the --extra_apks options to override the container keys. # Apply all the --extra_apks options to override the container keys.
for apex, key in OPTIONS.extra_apks.items(): for apex, key in OPTIONS.extra_apks.items():
@@ -293,13 +293,13 @@ def GetApexKeys(keys_info, key_map):
continue continue
if not key: if not key:
key = 'PRESIGNED' key = 'PRESIGNED'
keys_info[apex] = (keys_info[apex][0], key_map.get(key, key)) keys_info[apex] = (keys_info[apex][0], key_map.get(key, key), keys_info[apex][2])
# A PRESIGNED container entails a PRESIGNED payload. Apply this to all the # A PRESIGNED container entails a PRESIGNED payload. Apply this to all the
# APEX key pairs. However, a PRESIGNED container with non-PRESIGNED payload # APEX key pairs. However, a PRESIGNED container with non-PRESIGNED payload
# (overridden via commandline) indicates a config error, which should not be # (overridden via commandline) indicates a config error, which should not be
# allowed. # allowed.
for apex, (payload_key, container_key) in keys_info.items(): for apex, (payload_key, container_key, sign_tool) in keys_info.items():
if container_key != 'PRESIGNED': if container_key != 'PRESIGNED':
continue continue
if apex in OPTIONS.extra_apex_payload_keys: if apex in OPTIONS.extra_apex_payload_keys:
@@ -311,7 +311,7 @@ def GetApexKeys(keys_info, key_map):
print( print(
"Setting {} payload as PRESIGNED due to PRESIGNED container".format( "Setting {} payload as PRESIGNED due to PRESIGNED container".format(
apex)) apex))
keys_info[apex] = ('PRESIGNED', 'PRESIGNED') keys_info[apex] = ('PRESIGNED', 'PRESIGNED', None)
return keys_info return keys_info
@@ -372,7 +372,7 @@ def CheckApkAndApexKeysAvailable(input_tf_zip, known_keys,
compressed_extension: The extension string of compressed APKs, such as compressed_extension: The extension string of compressed APKs, such as
'.gz', or None if there's no compressed APKs. '.gz', or None if there's no compressed APKs.
apex_keys: A dict that contains the key mapping from APEX name to apex_keys: A dict that contains the key mapping from APEX name to
(payload_key, container_key). (payload_key, container_key, sign_tool).
Raises: Raises:
AssertionError: On finding unknown APKs and APEXes. AssertionError: On finding unknown APKs and APEXes.
@@ -417,7 +417,7 @@ def CheckApkAndApexKeysAvailable(input_tf_zip, known_keys,
name = GetApexFilename(info.filename) name = GetApexFilename(info.filename)
(payload_key, container_key) = apex_keys[name] (payload_key, container_key, _) = apex_keys[name]
if ((payload_key in common.SPECIAL_CERT_STRINGS and if ((payload_key in common.SPECIAL_CERT_STRINGS and
container_key not in common.SPECIAL_CERT_STRINGS) or container_key not in common.SPECIAL_CERT_STRINGS) or
(payload_key not in common.SPECIAL_CERT_STRINGS and (payload_key not in common.SPECIAL_CERT_STRINGS and
@@ -569,7 +569,7 @@ def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
elif IsApexFile(filename): elif IsApexFile(filename):
name = GetApexFilename(filename) name = GetApexFilename(filename)
payload_key, container_key = apex_keys[name] payload_key, container_key, sign_tool = apex_keys[name]
# We've asserted not having a case with only one of them PRESIGNED. # We've asserted not having a case with only one of them PRESIGNED.
if (payload_key not in common.SPECIAL_CERT_STRINGS and if (payload_key not in common.SPECIAL_CERT_STRINGS and
@@ -588,7 +588,8 @@ def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
apk_keys, apk_keys,
codename_to_api_level_map, codename_to_api_level_map,
no_hashtree=None, # Let apex_util determine if hash tree is needed no_hashtree=None, # Let apex_util determine if hash tree is needed
signing_args=OPTIONS.avb_extra_args.get('apex')) signing_args=OPTIONS.avb_extra_args.get('apex'),
sign_tool=sign_tool)
common.ZipWrite(output_tf_zip, signed_apex, filename) common.ZipWrite(output_tf_zip, signed_apex, filename)
else: else:
@@ -1147,15 +1148,16 @@ def ReadApexKeysInfo(tf_zip):
Given a target-files ZipFile, parses the META/apexkeys.txt entry and returns a Given a target-files ZipFile, parses the META/apexkeys.txt entry and returns a
dict that contains the mapping from APEX names (e.g. com.android.tzdata) to a dict that contains the mapping from APEX names (e.g. com.android.tzdata) to a
tuple of (payload_key, container_key). tuple of (payload_key, container_key, sign_tool).
Args: Args:
tf_zip: The input target_files ZipFile (already open). tf_zip: The input target_files ZipFile (already open).
Returns: Returns:
(payload_key, container_key): payload_key contains the path to the payload (payload_key, container_key, sign_tool):
signing key; container_key contains the path to the container signing - payload_key contains the path to the payload signing key
key. - container_key contains the path to the container signing key
- sign_tool is an apex-specific signing tool for its payload contents
""" """
keys = {} keys = {}
for line in tf_zip.read('META/apexkeys.txt').decode().split('\n'): for line in tf_zip.read('META/apexkeys.txt').decode().split('\n'):
@@ -1168,7 +1170,8 @@ def ReadApexKeysInfo(tf_zip):
r'private_key="(?P<PAYLOAD_PRIVATE_KEY>.*)"\s+' r'private_key="(?P<PAYLOAD_PRIVATE_KEY>.*)"\s+'
r'container_certificate="(?P<CONTAINER_CERT>.*)"\s+' r'container_certificate="(?P<CONTAINER_CERT>.*)"\s+'
r'container_private_key="(?P<CONTAINER_PRIVATE_KEY>.*?)"' r'container_private_key="(?P<CONTAINER_PRIVATE_KEY>.*?)"'
r'(\s+partition="(?P<PARTITION>.*?)")?$', r'(\s+partition="(?P<PARTITION>.*?)")?'
r'(\s+sign_tool="(?P<SIGN_TOOL>.*?)")?$',
line) line)
if not matches: if not matches:
continue continue
@@ -1197,7 +1200,8 @@ def ReadApexKeysInfo(tf_zip):
else: else:
raise ValueError("Failed to parse container keys: \n{}".format(line)) raise ValueError("Failed to parse container keys: \n{}".format(line))
keys[name] = (payload_private_key, container_key) sign_tool = matches.group("SIGN_TOOL")
keys[name] = (payload_private_key, container_key, sign_tool)
return keys return keys

View File

@@ -328,23 +328,23 @@ name="apex.apexd_test_different_app.apex" public_key="system/apex/apexd/apexd_te
'Apex3.apex' : 'key3', 'Apex3.apex' : 'key3',
} }
apex_keys = { apex_keys = {
'Apex1.apex' : ('payload-key1', 'container-key1'), 'Apex1.apex' : ('payload-key1', 'container-key1', None),
'Apex2.apex' : ('payload-key2', 'container-key2'), 'Apex2.apex' : ('payload-key2', 'container-key2', None),
} }
with zipfile.ZipFile(input_file) as input_zip: with zipfile.ZipFile(input_file) as input_zip:
CheckApkAndApexKeysAvailable(input_zip, apk_key_map, None, apex_keys) CheckApkAndApexKeysAvailable(input_zip, apk_key_map, None, apex_keys)
# Fine to have both keys as PRESIGNED. # Fine to have both keys as PRESIGNED.
apex_keys['Apex2.apex'] = ('PRESIGNED', 'PRESIGNED') apex_keys['Apex2.apex'] = ('PRESIGNED', 'PRESIGNED', None)
CheckApkAndApexKeysAvailable(input_zip, apk_key_map, None, apex_keys) CheckApkAndApexKeysAvailable(input_zip, apk_key_map, None, apex_keys)
# Having only one of them as PRESIGNED is not allowed. # Having only one of them as PRESIGNED is not allowed.
apex_keys['Apex2.apex'] = ('payload-key2', 'PRESIGNED') apex_keys['Apex2.apex'] = ('payload-key2', 'PRESIGNED', None)
self.assertRaises( self.assertRaises(
AssertionError, CheckApkAndApexKeysAvailable, input_zip, apk_key_map, AssertionError, CheckApkAndApexKeysAvailable, input_zip, apk_key_map,
None, apex_keys) None, apex_keys)
apex_keys['Apex2.apex'] = ('PRESIGNED', 'container-key1') apex_keys['Apex2.apex'] = ('PRESIGNED', 'container-key1', None)
self.assertRaises( self.assertRaises(
AssertionError, CheckApkAndApexKeysAvailable, input_zip, apk_key_map, AssertionError, CheckApkAndApexKeysAvailable, input_zip, apk_key_map,
None, apex_keys) None, apex_keys)
@@ -475,10 +475,10 @@ name="apex.apexd_test_different_app.apex" public_key="system/apex/apexd/apexd_te
self.assertEqual({ self.assertEqual({
'apex.apexd_test.apex': ( 'apex.apexd_test.apex': (
'system/apex/apexd/apexd_testdata/com.android.apex.test_package.pem', 'system/apex/apexd/apexd_testdata/com.android.apex.test_package.pem',
'build/make/target/product/security/testkey'), 'build/make/target/product/security/testkey', None),
'apex.apexd_test_different_app.apex': ( 'apex.apexd_test_different_app.apex': (
'system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.pem', 'system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.pem',
'build/make/target/product/security/testkey'), 'build/make/target/product/security/testkey', None),
}, keys_info) }, keys_info)
def test_ReadApexKeysInfo_mismatchingContainerKeys(self): def test_ReadApexKeysInfo_mismatchingContainerKeys(self):
@@ -514,10 +514,10 @@ name="apex.apexd_test_different_app.apex" public_key="system/apex/apexd/apexd_te
self.assertEqual({ self.assertEqual({
'apex.apexd_test.apex': ( 'apex.apexd_test.apex': (
'system/apex/apexd/apexd_testdata/com.android.apex.test_package.pem', 'system/apex/apexd/apexd_testdata/com.android.apex.test_package.pem',
'build/make/target/product/security/testkey'), 'build/make/target/product/security/testkey', None),
'apex.apexd_test_different_app.apex': ( 'apex.apexd_test_different_app.apex': (
'system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.pem', 'system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.pem',
'build/make/target/product/security/testkey'), 'build/make/target/product/security/testkey', None),
}, keys_info) }, keys_info)
def test_ReadApexKeysInfo_missingPayloadPublicKey(self): def test_ReadApexKeysInfo_missingPayloadPublicKey(self):
@@ -537,10 +537,10 @@ name="apex.apexd_test_different_app.apex" public_key="system/apex/apexd/apexd_te
self.assertEqual({ self.assertEqual({
'apex.apexd_test.apex': ( 'apex.apexd_test.apex': (
'system/apex/apexd/apexd_testdata/com.android.apex.test_package.pem', 'system/apex/apexd/apexd_testdata/com.android.apex.test_package.pem',
'build/make/target/product/security/testkey'), 'build/make/target/product/security/testkey', None),
'apex.apexd_test_different_app.apex': ( 'apex.apexd_test_different_app.apex': (
'system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.pem', 'system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.pem',
'build/make/target/product/security/testkey'), 'build/make/target/product/security/testkey', None),
}, keys_info) }, keys_info)
def test_ReadApexKeysInfo_presignedKeys(self): def test_ReadApexKeysInfo_presignedKeys(self):
@@ -560,10 +560,10 @@ name="apex.apexd_test_different_app.apex" public_key="system/apex/apexd/apexd_te
self.assertEqual({ self.assertEqual({
'apex.apexd_test.apex': ( 'apex.apexd_test.apex': (
'system/apex/apexd/apexd_testdata/com.android.apex.test_package.pem', 'system/apex/apexd/apexd_testdata/com.android.apex.test_package.pem',
'build/make/target/product/security/testkey'), 'build/make/target/product/security/testkey', None),
'apex.apexd_test_different_app.apex': ( 'apex.apexd_test_different_app.apex': (
'system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.pem', 'system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.pem',
'build/make/target/product/security/testkey'), 'build/make/target/product/security/testkey', None),
}, keys_info) }, keys_info)
def test_ReadApexKeysInfo_presignedKeys(self): def test_ReadApexKeysInfo_presignedKeys(self):
@@ -583,10 +583,10 @@ name="apex.apexd_test_different_app.apex" public_key="system/apex/apexd/apexd_te
self.assertEqual({ self.assertEqual({
'apex.apexd_test.apex': ( 'apex.apexd_test.apex': (
'system/apex/apexd/apexd_testdata/com.android.apex.test_package.pem', 'system/apex/apexd/apexd_testdata/com.android.apex.test_package.pem',
'build/make/target/product/security/testkey'), 'build/make/target/product/security/testkey', None),
'apex.apexd_test_different_app.apex': ( 'apex.apexd_test_different_app.apex': (
'system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.pem', 'system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.pem',
'build/make/target/product/security/testkey'), 'build/make/target/product/security/testkey', None),
}, keys_info) }, keys_info)
def test_ReplaceGkiSigningKey(self): def test_ReplaceGkiSigningKey(self):