Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8caba5e1 authored by Jooyung Han's avatar Jooyung Han
Browse files

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
parent 0f5a41da
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -4323,6 +4323,7 @@ INTERNAL_OTATOOLS_MODULES := \
  shflags \
  sign_apex \
  sign_target_files_apks \
  sign_virt_apex \
  signapk \
  simg2img \
  sload_f2fs \
+1 −0
Original line number Diff line number Diff line
@@ -142,6 +142,7 @@ class ApexApkSigner(object):
      has_signed_content = True

    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]
      common.RunAndCheckOutput(cmd)
      has_signed_content = True
+1 −1
Original line number Diff line number Diff line
@@ -2107,7 +2107,7 @@ def GetKeyPasswords(keylist):
  devnull = open("/dev/null", "w+b")
  for k in sorted(keylist):
    # 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)
      continue

+21 −17
Original line number Diff line number Diff line
@@ -262,7 +262,7 @@ def GetApexKeys(keys_info, key_map):

  Args:
    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.

  Returns:
@@ -280,11 +280,11 @@ def GetApexKeys(keys_info, key_map):
    if apex not in keys_info:
      logger.warning('Failed to find %s in target_files; Ignored', apex)
      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.
  for apex, (payload_key, container_key) in keys_info.items():
    keys_info[apex] = (payload_key, key_map.get(container_key, container_key))
  for apex, (payload_key, container_key, sign_tool) in keys_info.items():
    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.
  for apex, key in OPTIONS.extra_apks.items():
@@ -293,13 +293,13 @@ def GetApexKeys(keys_info, key_map):
      continue
    if not key:
      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
  # APEX key pairs. However, a PRESIGNED container with non-PRESIGNED payload
  # (overridden via commandline) indicates a config error, which should not be
  # 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':
      continue
    if apex in OPTIONS.extra_apex_payload_keys:
@@ -311,7 +311,7 @@ def GetApexKeys(keys_info, key_map):
      print(
          "Setting {} payload as PRESIGNED due to PRESIGNED container".format(
              apex))
    keys_info[apex] = ('PRESIGNED', 'PRESIGNED')
    keys_info[apex] = ('PRESIGNED', 'PRESIGNED', None)

  return keys_info

@@ -372,7 +372,7 @@ def CheckApkAndApexKeysAvailable(input_tf_zip, known_keys,
    compressed_extension: The extension string of compressed APKs, such as
        '.gz', or None if there's no compressed APKs.
    apex_keys: A dict that contains the key mapping from APEX name to
        (payload_key, container_key).
        (payload_key, container_key, sign_tool).

  Raises:
    AssertionError: On finding unknown APKs and APEXes.
@@ -417,7 +417,7 @@ def CheckApkAndApexKeysAvailable(input_tf_zip, known_keys,

    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
         container_key not in common.SPECIAL_CERT_STRINGS) or
        (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):
      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.
      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,
            codename_to_api_level_map,
            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)

      else:
@@ -1147,15 +1148,16 @@ def ReadApexKeysInfo(tf_zip):

  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
  tuple of (payload_key, container_key).
  tuple of (payload_key, container_key, sign_tool).

  Args:
    tf_zip: The input target_files ZipFile (already open).

  Returns:
    (payload_key, container_key): payload_key contains the path to the payload
        signing key; container_key contains the path to the container signing
        key.
    (payload_key, container_key, sign_tool):
      - payload_key contains the path to the payload signing key
      - container_key contains the path to the container signing key
      - sign_tool is an apex-specific signing tool for its payload contents
  """
  keys = {}
  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'container_certificate="(?P<CONTAINER_CERT>.*)"\s+'
        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)
    if not matches:
      continue
@@ -1197,7 +1200,8 @@ def ReadApexKeysInfo(tf_zip):
    else:
      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

+15 −15
Original line number Diff line number Diff line
@@ -328,23 +328,23 @@ name="apex.apexd_test_different_app.apex" public_key="system/apex/apexd/apexd_te
        'Apex3.apex' : 'key3',
    }
    apex_keys = {
        'Apex1.apex' : ('payload-key1', 'container-key1'),
        'Apex2.apex' : ('payload-key2', 'container-key2'),
        'Apex1.apex' : ('payload-key1', 'container-key1', None),
        'Apex2.apex' : ('payload-key2', 'container-key2', None),
    }
    with zipfile.ZipFile(input_file) as input_zip:
      CheckApkAndApexKeysAvailable(input_zip, apk_key_map, None, apex_keys)

      # 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)

      # 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(
          AssertionError, CheckApkAndApexKeysAvailable, input_zip, apk_key_map,
          None, apex_keys)

      apex_keys['Apex2.apex'] = ('PRESIGNED', 'container-key1')
      apex_keys['Apex2.apex'] = ('PRESIGNED', 'container-key1', None)
      self.assertRaises(
          AssertionError, CheckApkAndApexKeysAvailable, input_zip, apk_key_map,
          None, apex_keys)
@@ -475,10 +475,10 @@ name="apex.apexd_test_different_app.apex" public_key="system/apex/apexd/apexd_te
    self.assertEqual({
        'apex.apexd_test.apex': (
            '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': (
            '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)

  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({
        'apex.apexd_test.apex': (
            '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': (
            '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)

  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({
        'apex.apexd_test.apex': (
            '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': (
            '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)

  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({
        'apex.apexd_test.apex': (
            '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': (
            '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)

  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({
        'apex.apexd_test.apex': (
            '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': (
            '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)

  def test_ReplaceGkiSigningKey(self):