Example #1
0
def main(argv):

    options = {}

    def option_handler(o, a):
        if o == '--container_key':
            # Strip the suffix if any, as common.SignFile expects no suffix.
            DEFAULT_CONTAINER_KEY_SUFFIX = '.x509.pem'
            if a.endswith(DEFAULT_CONTAINER_KEY_SUFFIX):
                a = a[:-len(DEFAULT_CONTAINER_KEY_SUFFIX)]
            options['container_key'] = a
        elif o == '--payload_key':
            options['payload_key'] = a
        elif o == '--payload_extra_args':
            options['payload_extra_args'] = a
        else:
            return False
        return True

    args = common.ParseOptions(argv,
                               __doc__,
                               extra_opts='',
                               extra_long_opts=[
                                   'container_key=',
                                   'payload_extra_args=',
                                   'payload_key=',
                               ],
                               extra_option_handler=option_handler)

    if (len(args) != 2 or 'container_key' not in options
            or 'payload_key' not in options):
        common.Usage(__doc__)
        sys.exit(1)

    common.InitLogging()

    input_zip = args[0]
    output_zip = args[1]
    with open(input_zip) as input_fp:
        apex_data = input_fp.read()

    signed_apex = apex_utils.SignApex(
        apex_data,
        payload_key=options['payload_key'],
        container_key=options['container_key'],
        container_pw=None,
        codename_to_api_level_map=None,
        signing_args=options.get('payload_extra_args'))

    shutil.copyfile(signed_apex, output_zip)
    logger.info("done.")
Example #2
0
def SignApexFile(avbtool, apex_file, payload_key, container_key, no_hashtree,
                 apk_keys=None, signing_args=None, codename_to_api_level_map=None, sign_tool=None):
  """Signs the given apex file."""
  with open(apex_file, 'rb') as input_fp:
    apex_data = input_fp.read()

  return apex_utils.SignApex(
      avbtool,
      apex_data,
      payload_key=payload_key,
      container_key=container_key,
      container_pw=None,
      codename_to_api_level_map=codename_to_api_level_map,
      no_hashtree=no_hashtree,
      apk_keys=apk_keys,
      signing_args=signing_args,
      sign_tool=sign_tool)
Example #3
0
def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
                       apk_keys, apex_keys, key_passwords,
                       platform_api_level, codename_to_api_level_map,
                       compressed_extension):
  # maxsize measures the maximum filename length, including the ones to be
  # skipped.
  maxsize = max(
      [len(os.path.basename(i.filename)) for i in input_tf_zip.infolist()
       if GetApkFileInfo(i.filename, compressed_extension, [])[0]])
  system_root_image = misc_info.get("system_root_image") == "true"

  for info in input_tf_zip.infolist():
    filename = info.filename
    if filename.startswith("IMAGES/"):
      continue

    # Skip split super images, which will be re-generated during signing.
    if filename.startswith("OTA/") and filename.endswith(".img"):
      continue

    data = input_tf_zip.read(filename)
    out_info = copy.copy(info)
    (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
        filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)

    if is_apk and should_be_skipped:
      # Copy skipped APKs verbatim.
      print(
          "NOT signing: %s\n"
          "        (skipped due to matching prefix)" % (filename,))
      common.ZipWriteStr(output_tf_zip, out_info, data)

    # Sign APKs.
    elif is_apk:
      name = os.path.basename(filename)
      if is_compressed:
        name = name[:-len(compressed_extension)]

      key = apk_keys[name]
      if key not in common.SPECIAL_CERT_STRINGS:
        print("    signing: %-*s (%s)" % (maxsize, name, key))
        signed_data = SignApk(data, key, key_passwords[key], platform_api_level,
                              codename_to_api_level_map, is_compressed)
        common.ZipWriteStr(output_tf_zip, out_info, signed_data)
      else:
        # an APK we're not supposed to sign.
        print(
            "NOT signing: %s\n"
            "        (skipped due to special cert string)" % (name,))
        common.ZipWriteStr(output_tf_zip, out_info, data)

    # Sign bundled APEX files.
    elif filename.startswith("SYSTEM/apex") and filename.endswith(".apex"):
      name = os.path.basename(filename)
      payload_key, container_key = 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
          container_key not in common.SPECIAL_CERT_STRINGS):
        print("    signing: %-*s container (%s)" % (
            maxsize, name, container_key))
        print("           : %-*s payload   (%s)" % (
            maxsize, name, payload_key))

        signed_apex = apex_utils.SignApex(
            data,
            payload_key,
            container_key,
            key_passwords[container_key],
            codename_to_api_level_map,
            OPTIONS.avb_extra_args.get('apex'))
        common.ZipWrite(output_tf_zip, signed_apex, filename)

      else:
        print(
            "NOT signing: %s\n"
            "        (skipped due to special cert string)" % (name,))
        common.ZipWriteStr(output_tf_zip, out_info, data)

    # AVB public keys for the installed APEXes, which will be updated later.
    elif (os.path.dirname(filename) == 'SYSTEM/etc/security/apex' and
          filename != 'SYSTEM/etc/security/apex/'):
      continue

    # System properties.
    elif filename in ("SYSTEM/build.prop",
                      "VENDOR/build.prop",
                      "SYSTEM/vendor/build.prop",
                      "ODM/build.prop",  # legacy
                      "ODM/etc/build.prop",
                      "VENDOR/odm/build.prop",  # legacy
                      "VENDOR/odm/etc/build.prop",
                      "PRODUCT/build.prop",
                      "SYSTEM/product/build.prop",
                      "PRODUCT_SERVICES/build.prop",
                      "SYSTEM/product_services/build.prop",
                      "SYSTEM/etc/prop.default",
                      "BOOT/RAMDISK/prop.default",
                      "BOOT/RAMDISK/default.prop",  # legacy
                      "ROOT/default.prop",  # legacy
                      "RECOVERY/RAMDISK/prop.default",
                      "RECOVERY/RAMDISK/default.prop"):  # legacy
      print("Rewriting %s:" % (filename,))
      if stat.S_ISLNK(info.external_attr >> 16):
        new_data = data
      else:
        new_data = RewriteProps(data)
      common.ZipWriteStr(output_tf_zip, out_info, new_data)

    # Replace the certs in *mac_permissions.xml (there could be multiple, such
    # as {system,vendor}/etc/selinux/{plat,nonplat}_mac_permissions.xml).
    elif filename.endswith("mac_permissions.xml"):
      print("Rewriting %s with new keys." % (filename,))
      new_data = ReplaceCerts(data)
      common.ZipWriteStr(output_tf_zip, out_info, new_data)

    # Ask add_img_to_target_files to rebuild the recovery patch if needed.
    elif filename in ("SYSTEM/recovery-from-boot.p",
                      "SYSTEM/etc/recovery.img",
                      "SYSTEM/bin/install-recovery.sh"):
      OPTIONS.rebuild_recovery = True

    # Don't copy OTA certs if we're replacing them.
    elif (
        OPTIONS.replace_ota_keys and
        filename in (
            "BOOT/RAMDISK/system/etc/security/otacerts.zip",
            "BOOT/RAMDISK/system/etc/update_engine/update-payload-key.pub.pem",
            "RECOVERY/RAMDISK/system/etc/security/otacerts.zip",
            "SYSTEM/etc/security/otacerts.zip",
            "SYSTEM/etc/update_engine/update-payload-key.pub.pem")):
      pass

    # Skip META/misc_info.txt since we will write back the new values later.
    elif filename == "META/misc_info.txt":
      pass

    # Skip verity public key if we will replace it.
    elif (OPTIONS.replace_verity_public_key and
          filename in ("BOOT/RAMDISK/verity_key",
                       "ROOT/verity_key")):
      pass

    # Skip verity keyid (for system_root_image use) if we will replace it.
    elif OPTIONS.replace_verity_keyid and filename == "BOOT/cmdline":
      pass

    # Skip the care_map as we will regenerate the system/vendor images.
    elif filename == "META/care_map.pb" or filename == "META/care_map.txt":
      pass

    # Updates system_other.avbpubkey in /product/etc/.
    elif filename in (
        "PRODUCT/etc/security/avb/system_other.avbpubkey",
        "SYSTEM/product/etc/security/avb/system_other.avbpubkey"):
      # Only update system_other's public key, if the corresponding signing
      # key is specified via --avb_system_other_key.
      signing_key = OPTIONS.avb_keys.get("system_other")
      if signing_key:
        public_key = common.ExtractAvbPublicKey(signing_key)
        print("    Rewriting AVB public key of system_other in /product")
        common.ZipWrite(output_tf_zip, public_key, filename)

    # Should NOT sign boot-debug.img.
    elif filename in (
        "BOOT/RAMDISK/force_debuggable",
        "RECOVERY/RAMDISK/force_debuggable"
        "RECOVERY/RAMDISK/first_stage_ramdisk/force_debuggable"):
      raise common.ExternalError("debuggable boot.img cannot be signed")

    # A non-APK file; copy it verbatim.
    else:
      common.ZipWriteStr(output_tf_zip, out_info, data)

  if OPTIONS.replace_ota_keys:
    ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info)

  # Replace the keyid string in misc_info dict.
  if OPTIONS.replace_verity_private_key:
    ReplaceVerityPrivateKey(misc_info, OPTIONS.replace_verity_private_key[1])

  if OPTIONS.replace_verity_public_key:
    dest = "ROOT/verity_key" if system_root_image else "BOOT/RAMDISK/verity_key"
    # We are replacing the one in boot image only, since the one under
    # recovery won't ever be needed.
    ReplaceVerityPublicKey(
        output_tf_zip, dest, OPTIONS.replace_verity_public_key[1])

  # Replace the keyid string in BOOT/cmdline.
  if OPTIONS.replace_verity_keyid:
    ReplaceVerityKeyId(input_tf_zip, output_tf_zip,
                       OPTIONS.replace_verity_keyid[1])

  # Replace the AVB signing keys, if any.
  ReplaceAvbSigningKeys(misc_info)

  # Write back misc_info with the latest values.
  ReplaceMiscInfoTxt(input_tf_zip, output_tf_zip, misc_info)
def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
                       apk_keys, apex_keys, key_passwords,
                       platform_api_level, codename_to_api_level_map,
                       compressed_extension):
  # maxsize measures the maximum filename length, including the ones to be
  # skipped.
  maxsize = max(
      [len(os.path.basename(i.filename)) for i in input_tf_zip.infolist()
       if GetApkFileInfo(i.filename, compressed_extension, [])[0]])
  system_root_image = misc_info.get("system_root_image") == "true"

  for info in input_tf_zip.infolist():
    filename = info.filename
    if filename.startswith("IMAGES/"):
      continue

    # Skip OTA-specific images (e.g. split super images), which will be
    # re-generated during signing.
    if filename.startswith("OTA/") and filename.endswith(".img"):
      continue

    data = input_tf_zip.read(filename)
    out_info = copy.copy(info)
    (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
        filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)

    if is_apk and should_be_skipped:
      # Copy skipped APKs verbatim.
      print(
          "NOT signing: %s\n"
          "        (skipped due to matching prefix)" % (filename,))
      common.ZipWriteStr(output_tf_zip, out_info, data)

    # Sign APKs.
    elif is_apk:
      name = os.path.basename(filename)
      if is_compressed:
        name = name[:-len(compressed_extension)]

      key = apk_keys[name]
      if key not in common.SPECIAL_CERT_STRINGS:
        print("    signing: %-*s (%s)" % (maxsize, name, key))
        signed_data = SignApk(data, key, key_passwords[key], platform_api_level,
                              codename_to_api_level_map, is_compressed)
        common.ZipWriteStr(output_tf_zip, out_info, signed_data)
      else:
        # an APK we're not supposed to sign.
        print(
            "NOT signing: %s\n"
            "        (skipped due to special cert string)" % (name,))
        common.ZipWriteStr(output_tf_zip, out_info, data)

    # Sign bundled APEX files.
    elif filename.startswith("SYSTEM/apex") and filename.endswith(".apex"):
      name = os.path.basename(filename)
      payload_key, container_key = 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
          container_key not in common.SPECIAL_CERT_STRINGS):
        print("    signing: %-*s container (%s)" % (
            maxsize, name, container_key))
        print("           : %-*s payload   (%s)" % (
            maxsize, name, payload_key))

        avbtool = misc_info['avb_avbtool'] if 'avb_avbtool' in misc_info else 'avbtool'
        signed_apex = apex_utils.SignApex(
            avbtool,
            data,
            payload_key,
            container_key,
            key_passwords[container_key],
            apk_keys,
            codename_to_api_level_map,
            no_hashtree=True,
            signing_args=OPTIONS.avb_extra_args.get('apex'))
        common.ZipWrite(output_tf_zip, signed_apex, filename)

      else:
        print(
            "NOT signing: %s\n"
            "        (skipped due to special cert string)" % (name,))
        common.ZipWriteStr(output_tf_zip, out_info, data)

    # AVB public keys for the installed APEXes, which will be updated later.
    elif (os.path.dirname(filename) == 'SYSTEM/etc/security/apex' and
          filename != 'SYSTEM/etc/security/apex/'):
      continue

    # System properties.
    elif filename in (
        "SYSTEM/build.prop",

        "VENDOR/build.prop",
        "SYSTEM/vendor/build.prop",

        "ODM/etc/build.prop",
        "VENDOR/odm/etc/build.prop",

        "PRODUCT/build.prop",
        "SYSTEM/product/build.prop",

        "SYSTEM_EXT/build.prop",
        "SYSTEM/system_ext/build.prop",

        "SYSTEM/etc/prop.default",
        "BOOT/RAMDISK/prop.default",
        "RECOVERY/RAMDISK/prop.default",

        # ROOT/default.prop is a legacy path, but may still exist for upgrading
        # devices that don't support `property_overrides_split_enabled`.
        "ROOT/default.prop",

        # RECOVERY/RAMDISK/default.prop is a legacy path, but will always exist
        # as a symlink in the current code. So it's a no-op here. Keeping the
        # path here for clarity.
        "RECOVERY/RAMDISK/default.prop"):
      print("Rewriting %s:" % (filename,))
      if stat.S_ISLNK(info.external_attr >> 16):
        new_data = data
      else:
        new_data = RewriteProps(data.decode())
      common.ZipWriteStr(output_tf_zip, out_info, new_data)

    # Replace the certs in *mac_permissions.xml (there could be multiple, such
    # as {system,vendor}/etc/selinux/{plat,nonplat}_mac_permissions.xml).
    elif filename.endswith("mac_permissions.xml"):
      print("Rewriting %s with new keys." % (filename,))
      new_data = ReplaceCerts(data.decode())
      common.ZipWriteStr(output_tf_zip, out_info, new_data)
    elif info.filename.startswith("SYSTEM/etc/permissions/"):
      print("rewriting %s with new keys." % info.filename)
      new_data = ReplaceCerts(data)
      common.ZipWriteStr(output_tf_zip, out_info, new_data)

    # Ask add_img_to_target_files to rebuild the recovery patch if needed.
    elif filename in ("SYSTEM/recovery-from-boot.p",
                      "VENDOR/recovery-from-boot.p",

                      "SYSTEM/etc/recovery.img",
                      "VENDOR/etc/recovery.img",

                      "SYSTEM/bin/install-recovery.sh",
                      "VENDOR/bin/install-recovery.sh"):
      OPTIONS.rebuild_recovery = True

    # Don't copy OTA certs if we're replacing them.
    # Replacement of update-payload-key.pub.pem was removed in b/116660991.
    elif (
        OPTIONS.replace_ota_keys and
        filename in (
            "BOOT/RAMDISK/system/etc/security/otacerts.zip",
            "RECOVERY/RAMDISK/system/etc/security/otacerts.zip",
            "SYSTEM/etc/security/otacerts.zip")):
      pass

    # Skip META/misc_info.txt since we will write back the new values later.
    elif filename == "META/misc_info.txt":
      pass

    # Skip verity public key if we will replace it.
    elif (OPTIONS.replace_verity_public_key and
          filename in ("BOOT/RAMDISK/verity_key",
                       "ROOT/verity_key")):
      pass
    elif (OPTIONS.remove_avb_public_keys and
          (filename.startswith("BOOT/RAMDISK/avb/") or
           filename.startswith("BOOT/RAMDISK/first_stage_ramdisk/avb/"))):
        matched_removal = False
        for key_to_remove in OPTIONS.remove_avb_public_keys:
          if filename.endswith(key_to_remove):
            matched_removal = True
            print("Removing AVB public key from ramdisk: %s" % filename)
            break
        if not matched_removal:
          # Copy it verbatim if we don't want to remove it.
          common.ZipWriteStr(output_tf_zip, out_info, data)

    # Skip verity keyid (for system_root_image use) if we will replace it.
    elif OPTIONS.replace_verity_keyid and filename == "BOOT/cmdline":
      pass

    # Skip the care_map as we will regenerate the system/vendor images.
    elif filename == "META/care_map.pb" or filename == "META/care_map.txt":
      pass

    # Updates system_other.avbpubkey in /product/etc/.
    elif filename in (
        "PRODUCT/etc/security/avb/system_other.avbpubkey",
        "SYSTEM/product/etc/security/avb/system_other.avbpubkey"):
      # Only update system_other's public key, if the corresponding signing
      # key is specified via --avb_system_other_key.
      signing_key = OPTIONS.avb_keys.get("system_other")
      if signing_key:
        avbtool = misc_info['avb_avbtool'] if 'avb_avbtool' in misc_info else 'avbtool'
        public_key = common.ExtractAvbPublicKey(
            avbtool, signing_key)
        print("    Rewriting AVB public key of system_other in /product")
        common.ZipWrite(output_tf_zip, public_key, filename)

    # Should NOT sign boot-debug.img.
    elif filename in (
        "BOOT/RAMDISK/force_debuggable",
        "BOOT/RAMDISK/first_stage_ramdisk/force_debuggable"):
      raise common.ExternalError("debuggable boot.img cannot be signed")

    # A non-APK file; copy it verbatim.
    else:
      common.ZipWriteStr(output_tf_zip, out_info, data)

  if OPTIONS.replace_ota_keys:
    ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info)

  # Replace the keyid string in misc_info dict.
  if OPTIONS.replace_verity_private_key:
    ReplaceVerityPrivateKey(misc_info, OPTIONS.replace_verity_private_key[1])

  if OPTIONS.replace_verity_public_key:
    # Replace the one in root dir in system.img.
    ReplaceVerityPublicKey(
        output_tf_zip, 'ROOT/verity_key', OPTIONS.replace_verity_public_key[1])

    if not system_root_image:
      # Additionally replace the copy in ramdisk if not using system-as-root.
      ReplaceVerityPublicKey(
          output_tf_zip,
          'BOOT/RAMDISK/verity_key',
          OPTIONS.replace_verity_public_key[1])

  # Replace the keyid string in BOOT/cmdline.
  if OPTIONS.replace_verity_keyid:
    ReplaceVerityKeyId(input_tf_zip, output_tf_zip,
                       OPTIONS.replace_verity_keyid[1])

  # Replace the AVB signing keys, if any.
  ReplaceAvbSigningKeys(misc_info)

  # Rewrite the props in AVB signing args.
  if misc_info.get('avb_enable') == 'true':
    RewriteAvbProps(misc_info)

  # Write back misc_info with the latest values.
  ReplaceMiscInfoTxt(input_tf_zip, output_tf_zip, misc_info)