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

Commit ca96bcb0 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Sign OTA packages inside target_files during signing" into main

parents 952df85c b84d2aa7
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -333,6 +333,7 @@ python_library_host {
    srcs: [
        "ota_utils.py",
        "payload_signer.py",
        "ota_signing_utils.py",
    ],
    libs: [
        "releasetools_common",
@@ -348,7 +349,6 @@ python_binary_host {
    },
    srcs: [
        "merge_ota.py",
        "ota_signing_utils.py",
    ],
    libs: [
        "ota_metadata_proto",
@@ -501,7 +501,6 @@ python_binary_host {
    name: "ota_from_raw_img",
    srcs: [
        "ota_from_raw_img.py",
        "ota_signing_utils.py",
    ],
    main: "ota_from_raw_img.py",
    defaults: [
@@ -552,6 +551,8 @@ python_binary_host {
    defaults: ["releasetools_binary_defaults"],
    srcs: [
        "sign_target_files_apks.py",
        "payload_signer.py",
        "ota_signing_utils.py",
    ],
    libs: [
        "releasetools_add_img_to_target_files",
@@ -615,7 +616,6 @@ python_defaults {
        "sign_target_files_apks.py",
        "validate_target_files.py",
        "merge_ota.py",
        "ota_signing_utils.py",
        ":releasetools_merge_sources",
        ":releasetools_merge_tests",

+21 −6
Original line number Diff line number Diff line
@@ -3105,8 +3105,7 @@ def ZipWriteStr(zip_file, zinfo_or_arcname, data, perms=None,
  zip_file.writestr(zinfo, data)
  zipfile.ZIP64_LIMIT = saved_zip64_limit


def ZipDelete(zip_filename, entries, force=False):
def ZipExclude(input_zip, output_zip, entries, force=False):
  """Deletes entries from a ZIP file.

  Args:
@@ -3117,22 +3116,38 @@ def ZipDelete(zip_filename, entries, force=False):
    entries = [entries]
  # If list is empty, nothing to do
  if not entries:
    shutil.copy(input_zip, output_zip)
    return

  with zipfile.ZipFile(zip_filename, 'r') as zin:
  with zipfile.ZipFile(input_zip, 'r') as zin:
    if not force and len(set(zin.namelist()).intersection(entries)) == 0:
      raise ExternalError(
          "Failed to delete zip entries, name not matched: %s" % entries)

    fd, new_zipfile = tempfile.mkstemp(dir=os.path.dirname(zip_filename))
    fd, new_zipfile = tempfile.mkstemp(dir=os.path.dirname(input_zip))
    os.close(fd)
    cmd = ["zip2zip", "-i", zip_filename, "-o", new_zipfile]
    cmd = ["zip2zip", "-i", input_zip, "-o", new_zipfile]
    for entry in entries:
      cmd.append("-x")
      cmd.append(entry)
    RunAndCheckOutput(cmd)
  os.replace(new_zipfile, output_zip)


def ZipDelete(zip_filename, entries, force=False):
  """Deletes entries from a ZIP file.

  Args:
    zip_filename: The name of the ZIP file.
    entries: The name of the entry, or the list of names to be deleted.
  """
  if isinstance(entries, str):
    entries = [entries]
  # If list is empty, nothing to do
  if not entries:
    return

  os.replace(new_zipfile, zip_filename)
  ZipExclude(zip_filename, zip_filename, entries, force)


def ZipClose(zip_file):
+5 −9
Original line number Diff line number Diff line
@@ -27,7 +27,8 @@ from common import (ZipDelete, DoesInputFileContain, ReadBytesFromInputFile, OPT
                    ZipWriteStr, BuildInfo, LoadDictionaryFromFile,
                    SignFile, PARTITIONS_WITH_BUILD_PROP, PartitionBuildProps,
                    GetRamdiskFormat, ParseUpdateEngineConfig)
from payload_signer import PayloadSigner
import payload_signer
from payload_signer import PayloadSigner, AddSigningArgumentParse, GeneratePayloadProperties


logger = logging.getLogger(__name__)
@@ -785,8 +786,8 @@ def GetPartitionMaps(target_files_dir: str, ab_partitions):
class PayloadGenerator(object):
  """Manages the creation and the signing of an A/B OTA Payload."""

  PAYLOAD_BIN = 'payload.bin'
  PAYLOAD_PROPERTIES_TXT = 'payload_properties.txt'
  PAYLOAD_BIN = payload_signer.PAYLOAD_BIN
  PAYLOAD_PROPERTIES_TXT = payload_signer.PAYLOAD_PROPERTIES_TXT
  SECONDARY_PAYLOAD_BIN = 'secondary/payload.bin'
  SECONDARY_PAYLOAD_PROPERTIES_TXT = 'secondary/payload_properties.txt'

@@ -905,12 +906,7 @@ class PayloadGenerator(object):
    """
    assert self.payload_file is not None
    # 4. Dump the signed payload properties.
    properties_file = common.MakeTempFile(prefix="payload-properties-",
                                          suffix=".txt")
    cmd = ["delta_generator",
           "--in_file=" + self.payload_file,
           "--properties_file=" + properties_file]
    self._Run(cmd)
    properties_file = GeneratePayloadProperties(self.payload_file)


    with open(properties_file, "a") as f:
+56 −0
Original line number Diff line number Diff line
@@ -17,7 +17,12 @@
import common
import logging
import shlex
import argparse
import tempfile
import zipfile
import shutil
from common import OPTIONS, OptionHandler
from ota_signing_utils import AddSigningArgumentParse

logger = logging.getLogger(__name__)

@@ -26,6 +31,8 @@ OPTIONS.payload_signer_args = []
OPTIONS.payload_signer_maximum_signature_size = None
OPTIONS.package_key = None

PAYLOAD_BIN = 'payload.bin'
PAYLOAD_PROPERTIES_TXT = 'payload_properties.txt'

class SignerOptions(OptionHandler):

@@ -165,3 +172,52 @@ class PayloadSigner(object):
    cmd = [self.signer] + self.signer_args + ['-in', in_file, '-out', out_file]
    common.RunAndCheckOutput(cmd)
    return out_file

def GeneratePayloadProperties(payload_file):
    properties_file = common.MakeTempFile(prefix="payload-properties-",
                                          suffix=".txt")
    cmd = ["delta_generator",
           "--in_file=" + payload_file,
           "--properties_file=" + properties_file]
    common.RunAndCheckOutput(cmd)
    return properties_file

def SignOtaPackage(input_path, output_path):
  payload_signer = PayloadSigner(
      OPTIONS.package_key, OPTIONS.private_key_suffix,
      None, OPTIONS.payload_signer, OPTIONS.payload_signer_args)
  common.ZipExclude(input_path, output_path, [PAYLOAD_BIN, PAYLOAD_PROPERTIES_TXT])
  with tempfile.NamedTemporaryFile() as unsigned_payload, zipfile.ZipFile(input_path, "r", allowZip64=True) as zfp:
    with zfp.open("payload.bin") as payload_fp:
      shutil.copyfileobj(payload_fp, unsigned_payload)
    signed_payload = payload_signer.SignPayload(unsigned_payload.name)
    properties_file = GeneratePayloadProperties(signed_payload)
    with zipfile.ZipFile(output_path, "a", compression=zipfile.ZIP_STORED, allowZip64=True) as output_zfp:
      common.ZipWrite(output_zfp, signed_payload, PAYLOAD_BIN)
      common.ZipWrite(output_zfp, properties_file, PAYLOAD_PROPERTIES_TXT)


def main(argv):
  parser = argparse.ArgumentParser(
      prog=argv[0], description="Given a series of .img files, produces a full OTA package that installs thoese images")
  parser.add_argument("input_ota", type=str,
                      help="Input OTA for signing")
  parser.add_argument('output_ota', type=str,
                      help='Output OTA for the signed package')
  parser.add_argument("-v", action="store_true",
                      help="Enable verbose logging", dest="verbose")
  AddSigningArgumentParse(parser)
  args = parser.parse_args(argv[1:])
  input_ota = args.input_ota
  output_ota = args.output_ota
  if args.verbose:
    OPTIONS.verbose = True
  common.InitLogging()
  if args.package_key:
    OPTIONS.package_key = args.package_key
  logger.info("Re-signing OTA package {}".format(input_ota))
  SignOtaPackage(input_ota, output_ota)

if __name__ == "__main__":
  import sys
  main(sys.argv)
 No newline at end of file
+60 −3
Original line number Diff line number Diff line
@@ -146,6 +146,34 @@ Usage: sign_target_files_apks [flags] input_target_files output_target_files

  --override_apex_keys <path>
      Replace all APEX keys with this private key

  -k  (--package_key) <key>
      Key to use to sign the package (default is the value of
      default_system_dev_certificate from the input target-files's
      META/misc_info.txt, or "build/make/target/product/security/testkey" if
      that value is not specified).

      For incremental OTAs, the default value is based on the source
      target-file, not the target build.

  --payload_signer <signer>
      Specify the signer when signing the payload and metadata for A/B OTAs.
      By default (i.e. without this flag), it calls 'openssl pkeyutl' to sign
      with the package private key. If the private key cannot be accessed
      directly, a payload signer that knows how to do that should be specified.
      The signer will be supplied with "-inkey <path_to_key>",
      "-in <input_file>" and "-out <output_file>" parameters.

  --payload_signer_args <args>
      Specify the arguments needed for payload signer.

  --payload_signer_maximum_signature_size <signature_size>
      The maximum signature size (in bytes) that would be generated by the given
      payload signer. Only meaningful when custom payload signer is specified
      via '--payload_signer'.
      If the signer uses a RSA key, this should be the number of bytes to
      represent the modulus. If it uses an EC key, this is the size of a
      DER-encoded ECDSA signature.
"""

from __future__ import print_function
@@ -161,7 +189,6 @@ import os
import re
import shutil
import stat
import subprocess
import sys
import tempfile
import zipfile
@@ -170,6 +197,8 @@ from xml.etree import ElementTree
import add_img_to_target_files
import apex_utils
import common
import payload_signer
from payload_signer import SignOtaPackage, PAYLOAD_BIN


if sys.hexversion < 0x02070000:
@@ -240,6 +269,20 @@ def IsApexFile(filename):
  return filename.endswith(".apex") or filename.endswith(".capex")


def IsOtaPackage(fp):
  with zipfile.ZipFile(fp) as zfp:
    if not PAYLOAD_BIN in zfp.namelist():
      return False
    with zfp.open(PAYLOAD_BIN, "r") as payload:
      magic = payload.read(4)
      return magic == b"CrAU"


def IsEntryOtaPackage(input_zip, filename):
  with input_zip.open(filename, "r") as fp:
    return IsOtaPackage(fp)


def GetApexFilename(filename):
  name = os.path.basename(filename)
  # Replace the suffix for compressed apex
@@ -514,6 +557,7 @@ def SignApk(data, keyname, pw, platform_api_level, codename_to_api_level_map,
  return data



def IsBuildPropFile(filename):
  return filename in (
      "SYSTEM/etc/prop.default",
@@ -540,7 +584,7 @@ def IsBuildPropFile(filename):
        filename.endswith("/prop.default")


def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
def ProcessTargetFiles(input_tf_zip: zipfile.ZipFile, output_tf_zip, misc_info,
                       apk_keys, apex_keys, key_passwords,
                       platform_api_level, codename_to_api_level_map,
                       compressed_extension):
@@ -628,6 +672,15 @@ def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
            "        (skipped due to special cert string)" % (name,))
        common.ZipWriteStr(output_tf_zip, out_info, data)

    elif filename.endswith(".zip") and IsEntryOtaPackage(input_tf_zip, filename):
      logger.info("Re-signing OTA package {}".format(filename))
      with tempfile.NamedTemporaryFile() as input_ota, tempfile.NamedTemporaryFile() as output_ota:
        with input_tf_zip.open(filename, "r") as in_fp:
          shutil.copyfileobj(in_fp, input_ota)
          input_ota.flush()
        SignOtaPackage(input_ota.name, output_ota.name)
        common.ZipWrite(output_tf_zip, output_ota.name, filename,
                        compress_type=zipfile.ZIP_STORED)
    # System properties.
    elif IsBuildPropFile(filename):
      print("Rewriting %s:" % (filename,))
@@ -1501,7 +1554,7 @@ def main(argv):
          "override_apk_keys=",
          "override_apex_keys=",
      ],
      extra_option_handler=option_handler)
      extra_option_handler=[option_handler, payload_signer.signer_options])

  if len(args) != 2:
    common.Usage(__doc__)
@@ -1515,6 +1568,10 @@ def main(argv):
                               allowZip64=True)

  misc_info = common.LoadInfoDict(input_zip)
  if OPTIONS.package_key is None:
      OPTIONS.package_key = misc_info.get(
          "default_system_dev_certificate",
          "build/make/target/product/security/testkey")

  BuildKeyMap(misc_info, key_mapping_options)