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

Commit 9d9de379 authored by Tao Bao's avatar Tao Bao
Browse files

Revert "Add ability to sign bundled APEX into device signing process."

This reverts commit b3517c0d.

Bug: 123716522
Test: N/A (done with the re-landing CLs)
Change-Id: I6e6232826b7b1eadce435ef88afdd51ade49fcf0
parent 35a7add4
Loading
Loading
Loading
Loading

tools/releasetools/apex_utils.py

deleted100644 → 0
+0 −146
Original line number Diff line number Diff line
#!/usr/bin/env python
#
# Copyright (C) 2019 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from __future__ import print_function
import logging
import os.path
import re
import tempfile
import zipfile

import common

logger = logging.getLogger(__name__)

OPTIONS = common.OPTIONS
BLOCK_SIZE = common.BLOCK_SIZE

class ApexInfoError(Exception):
  """An Exception raised during Apex Information command."""

  def __init__(self, message):
    Exception.__init__(self, message)


class ApexSigningError(Exception):
  """An Exception raised during Apex Payload signing."""

  def __init__(self, message):
    Exception.__init__(self, message)


class ApexPayloadSignerHelper(object):
  """An Apex Payload Signer helper class."""

  def __init__(self, apex_payload_data):
    self.avbtool = 'avbtool'
    self.apex_payload_file = tempfile.NamedTemporaryFile()
    self.apex_payload_file.write(apex_payload_data)
    self.apex_payload_file.flush()
    self.payload_image_info_helper = ApexInfoHelper()
    self.payload_image_info_helper.SetImageInfo(self.avbtool,
                                                self.apex_payload_file.name)

  def GetPayLoadImageInfo(self):
    return self.payload_image_info_helper.GetImageInfo()

  def StripExistingAVBMetaSignature(self, image_path):
    cmd = [self.avbtool, "erase_footer", "--image", image_path]
    proc = common.Run(cmd)
    output, _ = proc.communicate()
    if proc.returncode != 0:
      raise ApexInfoError(
          "Unable to erase VBMeta footer:\n{}".format(output))

  def Verify(self, image_key):
    cmd = [self.avbtool, "verify_image",
           "--image", self.apex_payload_file.name,
           "--key", image_key]
    proc = common.Run(cmd)
    output, _ = proc.communicate()
    if proc.returncode != 0:
      raise ApexSigningError(
          "Unable to validate Image Signing:\n{}".format(output))

  def Sign(self, package_name, image_key, signing_args=None):
    # Strip any existing VBMeta signature/footers.
    try:
      self.StripExistingAVBMetaSignature(self.apex_payload_file.name)
    except ApexInfoError:
      print ("Unable to strip existing VBMeta Signature.")
      raise

    algorithm = self.GetPayLoadImageInfo().get('Algorithm',
                                               OPTIONS.avb_algorithms.get('apex'))
    assert algorithm, 'Missing AVB signing algorithm for %s' % (package_name,)

    salt = self.GetPayLoadImageInfo().get('Salt')

    cmd = [self.avbtool, "add_hashtree_footer",
           "--do_not_generate_fec",
           "--algorithm", algorithm,
           "--key", image_key,
           "--prop", "apex.key:%s" % package_name,
           "--image", self.apex_payload_file.name,
           "--salt", salt]
    if signing_args:
      cmd.extend([signing_args])

    proc = common.Run(cmd)
    output, _ = proc.communicate()
    if proc.returncode != 0:
      raise ApexSigningError(
          "Unable to sign Apex image:\n{}".format(output))

    # Verify the Signed Image with specified public key.
    print ("Verifying %s" % package_name)
    self.Verify(image_key)

    data = None
    with open(self.apex_payload_file.name) as af:
      data = af.read()
    return data


class ApexInfoHelper(object):
  """An Apex Info helper."""

  def __init__(self):
    self.image_info = {}

  def SetImageInfo(self, avbtool, image_path):
    if not os.path.exists(image_path):
      raise ApexInfoError(
          "Unable to find Image: %s" % image_path)

    cmd = [avbtool, "info_image", "--image", image_path]

    # Extract the Algorithm and Salt information from image.
    regex = re.compile('^\s*(?P<key>Algorithm|Salt)\:\s*(?P<value>.*?)$')

    proc = common.Run(cmd)
    for line in iter(proc.stdout.readline, b''):
      _item = regex.match(line)
      if _item:
        item_dict = _item.groupdict()
        self.image_info[item_dict['key']] = item_dict['value']
    output, _ = proc.communicate()
    if proc.returncode != 0:
      raise ApexInfoError(
          "Unable to fetch information:\n{}".format(output))

  def GetImageInfo(self):
    return self.image_info
+3 −132
Original line number Diff line number Diff line
@@ -85,16 +85,12 @@ Usage: sign_target_files_apks [flags] input_target_files output_target_files
      Replace the veritykeyid in BOOT/cmdline of input_target_file_zip
      with keyid of the cert pointed by <path_to_X509_PEM_cert_file>.

  --apex_payload_key <name=key>
      Add a mapping for apex package name to payload signing key.

  --avb_{apex,boot,system,vendor,dtbo,vbmeta}_algorithm <algorithm>

  --avb_{boot,system,vendor,dtbo,vbmeta}_algorithm <algorithm>
  --avb_{boot,system,vendor,dtbo,vbmeta}_key <key>
      Use the specified algorithm (e.g. SHA256_RSA4096) and the key to AVB-sign
      the specified image. Otherwise it uses the existing values in info dict.

  --avb_{apex,boot,system,vendor,dtbo,vbmeta}_extra_args <args>
  --avb_{boot,system,vendor,dtbo,vbmeta}_extra_args <args>
      Specify any additional args that are needed to AVB-sign the image
      (e.g. "--signing_helper /path/to/helper"). The args will be appended to
      the existing ones in info dict.
@@ -113,13 +109,11 @@ import shutil
import stat
import subprocess
import sys
import time
import tempfile
import zipfile
from xml.etree import ElementTree

import add_img_to_target_files
import apex_utils
import common


@@ -133,7 +127,6 @@ logger = logging.getLogger(__name__)
OPTIONS = common.OPTIONS

OPTIONS.extra_apks = {}
OPTIONS.apex_payload_keys = {}
OPTIONS.skip_apks_with_path_prefix = set()
OPTIONS.key_map = {}
OPTIONS.rebuild_recovery = False
@@ -299,79 +292,6 @@ def SignApk(data, keyname, pw, platform_api_level, codename_to_api_level_map,

  return data

def SignApex(data, name, image_key_path, container_key, pw,
             platform_api_level, codename_to_api_level_map):
  """Signing an Apex is a two step process.
  1: Extract and sign the image_payload.img with image_key.
  2: Sign the overall APK Container with container key.
  """
  unsigned_apex_payload = tempfile.NamedTemporaryFile()
  signed_apex_payload = tempfile.NamedTemporaryFile()
  unsigned_apex_payload.write(data)
  unsigned_apex_payload.flush()
  unsigned_apex_payload_zip = zipfile.ZipFile(
      unsigned_apex_payload.name, "r")
  signed_apex_payload_zip = zipfile.ZipFile(
      signed_apex_payload.name, "w",
      compression=zipfile.ZIP_DEFLATED,
      allowZip64=False)

  for info in unsigned_apex_payload_zip.infolist():
    filename = info.filename

    data = unsigned_apex_payload_zip.read(filename)
    out_info = copy.copy(info)

    if filename == 'apex_payload.img':
      package_name = re.sub('.apex', '', name)
      apex_sign_helper = apex_utils.ApexPayloadSignerHelper(
          data)

      extra_signing_args=OPTIONS.avb_extra_args.get('apex')
      key_path = '%s_pub.pem' % image_key_path
      signed_apex_payload_image = apex_sign_helper.Sign(
          package_name,
          key_path,
          extra_signing_args)

      common.ZipWriteStr(signed_apex_payload_zip,
                         out_info,
                         signed_apex_payload_image)
    else:
      common.ZipWriteStr(signed_apex_payload_zip,
                         out_info,
                         data)

  common.ZipClose(unsigned_apex_payload_zip)
  common.ZipClose(signed_apex_payload_zip)

  signed_container = tempfile.NamedTemporaryFile()
  signed_aligned_container = tempfile.NamedTemporaryFile()

  common.SignFile(
      signed_apex_payload.name,
      signed_container.name,
      container_key,
      pw,
      min_api_level=None,
      codename_to_api_level_map=codename_to_api_level_map)

  cmd = ['zipalign', '-f', '4096',
         signed_container.name,
         signed_aligned_container.name]
  proc = common.Run(cmd)
  output, _ = proc.communicate()
  if proc.returncode != 0:
    raise ApexInfoError(
      "Unable to zipalign apex container:\n{}".format(output))

  data = signed_aligned_container.read()
  signed_container.close()
  signed_aligned_container.close()
  signed_apex_payload.close()

  return data


def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
                       apk_key_map, key_passwords, platform_api_level,
@@ -386,7 +306,6 @@ def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,

  for info in input_tf_zip.infolist():
    filename = info.filename

    if filename.startswith("IMAGES/"):
      continue

@@ -483,43 +402,6 @@ def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
    elif filename == "META/care_map.pb" or filename == "META/care_map.txt":
      pass

    # Sign Bundled APEX files.
    elif filename.startswith("SYSTEM/apex") and filename.endswith(".apex"):
      name = os.path.basename(filename)
      # TODO(baligh): Read Apex Image and Container keys from
      # META/apexkeys.txt
      if name in OPTIONS.apex_payload_keys and name in OPTIONS.extra_apks:
        image_key_path = OPTIONS.apex_payload_keys[name]
        container_key_path = OPTIONS.extra_apks[name]
        print("    signing: %-*s (%s)" % (maxsize, name, container_key_path))
        print("           : %-*s (%s)" % (maxsize, 'image_payload', image_key_path))
        signed_data = SignApex(data,
                               name,
                               image_key_path,
                               container_key_path,
                               key_passwords[container_key_path],
                               platform_api_level,
                               codename_to_api_level_map)

        common.ZipWriteStr(output_tf_zip, out_info, signed_data)
      else:
        print("    signing: %-*s (NOT SIGNING)" % (maxsize, name))
        common.ZipWriteStr(output_tf_zip, out_info, data)

    elif ((os.path.dirname(filename) == "SYSTEM/etc/security/apex") and
          filename != 'SYSTEM/etc/security/apex/'):
      # AVBPubkey is used to validate APEX payload_image at load time.
      apex_name = '%s.apex' % os.path.basename(filename)
      if apex_name in OPTIONS.extra_apks:
        avb_pubkey_path = '%s.avbpubkey' % OPTIONS.apex_payload_keys[apex_name]
        print ("Replacing AVB PubKey for %s with %s" % (
            apex_name, avb_pubkey_path))
        with open(avb_pubkey_path) as cf:
          common.ZipWriteStr(output_tf_zip, out_info, cf.read())
      else:
        print ("Not Replacing AVB Pubkey for %s" % apex_name)
        common.ZipWriteStr(output_tf_zip, out_info, data)

    # A non-APK file; copy it verbatim.
    else:
      common.ZipWriteStr(output_tf_zip, out_info, data)
@@ -944,10 +826,7 @@ def main(argv):
  key_mapping_options = []

  def option_handler(o, a):
    if o == "--apex_payload_key":
      apex_name, key = a.split("=")
      OPTIONS.apex_payload_keys[apex_name] = key
    elif o in ("-e", "--extra_apks"):
    if o in ("-e", "--extra_apks"):
      names, key = a.split("=")
      names = names.split(",")
      for n in names:
@@ -986,8 +865,6 @@ def main(argv):
      OPTIONS.avb_extra_args['vbmeta'] = a
    elif o == "--avb_boot_key":
      OPTIONS.avb_keys['boot'] = a
    elif o == "--avb_apex_algorithm":
      OPTIONS.avb_algorithms['apex'] = a
    elif o == "--avb_boot_algorithm":
      OPTIONS.avb_algorithms['boot'] = a
    elif o == "--avb_boot_extra_args":
@@ -1010,8 +887,6 @@ def main(argv):
      OPTIONS.avb_algorithms['vendor'] = a
    elif o == "--avb_vendor_extra_args":
      OPTIONS.avb_extra_args['vendor'] = a
    elif o == "--avb_apex_extra_args":
      OPTIONS.avb_extra_args['apex'] = a
    else:
      return False
    return True
@@ -1021,7 +896,6 @@ def main(argv):
      extra_opts="e:d:k:ot:",
      extra_long_opts=[
          "extra_apks=",
          "apex_payload_key=",
          "skip_apks_with_path_prefix=",
          "default_key_mappings=",
          "key_mapping=",
@@ -1033,7 +907,6 @@ def main(argv):
          "avb_vbmeta_algorithm=",
          "avb_vbmeta_key=",
          "avb_vbmeta_extra_args=",
          "avb_apex_algorithm=",
          "avb_boot_algorithm=",
          "avb_boot_key=",
          "avb_boot_extra_args=",
@@ -1046,8 +919,6 @@ def main(argv):
          "avb_vendor_algorithm=",
          "avb_vendor_key=",
          "avb_vendor_extra_args=",
          "avb_apex_extra_args=",

      ],
      extra_option_handler=option_handler)