重启后恢复

在 Android 11 中,可以使用 A/B 更新虚拟 A/B 更新机制,结合 RecoverySystem 类方法来应用 OTA 更新。设备重启以应用 OTA 更新后,重启后恢复 (RoR) 会解锁设备的凭据加密 (CE) 存储

虽然合作伙伴可以将此过程与 OTA 系统功能配对,以便在 Android 11 中设备预计处于空闲状态时应用更新,但在 Android 12 中,合作伙伴无需额外的 OTA 系统功能。RoR 过程为用户提供了额外的安全性和便利性,因为更新可以在设备空闲时进行,而 Android 12 多客户端和基于服务器的更新功能共同提供了设备硬件级别的类型安全。

虽然您必须为 android.hardware.reboot_escrow 功能提供设备权限才能在 Android 11 中支持 RoR,但您无需这样做即可在 Android 12 及更高版本中启用基于服务器的 RoR,因为它们不使用 HAL。

背景

从 Android 7 开始,Android 支持 Direct Boot,这使设备上的应用能够在用户解锁 CE 存储之前启动。Direct Boot 支持的实现为用户提供了更好的体验,无需在启动后输入锁屏知识因素 (LSKF)。

RoR 允许解锁设备上所有应用的 CE 存储(包括那些不支持 Direct Boot 的应用),当在 OTA 更新后启动重启时。此功能使用户能够在重启后接收来自其所有已安装应用的通知。

威胁模型

RoR 的实现必须确保当设备落入攻击者手中时,即使设备已开机、CE 存储已解锁且在接收 OTA 更新后设备已由用户解锁,攻击者也很难恢复用户的 CE 加密数据。即使攻击者获得了对广播加密签名密钥的访问权限,内部攻击抵御能力也必须有效。

具体而言,物理持有设备且具有以下功能和限制的攻击者不得读取 CE 存储

功能

  • 可以使用任何供应商或公司的签名密钥来签署任意消息。
  • 可以使设备接收 OTA 更新。
  • 可以修改任何硬件(例如应用程序处理器或闪存)的运行,但以下限制中详述的硬件除外。(但是,此类修改涉及至少一小时的延迟,以及会破坏 RAM 内容的断电重启。)

限制

  • 无法修改防篡改硬件(例如 Titan M)的运行。
  • 无法读取实时设备的 RAM。
  • 无法猜测用户的凭据(PIN 码、图案、密码)或以其他方式导致用户输入凭据。

解决方案

Android 12 RoR 更新系统可针对非常复杂的攻击者提供安全保护,并且在设备密码和 PIN 码保留在设备上的同时实现这一点 — 它们永远不会发送到 Google 服务器或存储在 Google 服务器上。以下是确保提供的安全级别与基于硬件的设备级别 RoR 系统类似的过程概述

  • Android 对设备上存储的数据应用加密保护。
  • 所有数据都受到存储在可信执行环境 (TEE) 中的密钥的保护。
  • 只有当正在运行的操作系统通过加密身份验证(verified boot,已验证启动)时,TEE 才会释放密钥。
  • 在 Google 服务器上运行的 RoR 服务通过存储一个仅在有限时间内可以检索的密钥来保护 CE 数据。这适用于整个 Android 生态系统。
  • 受用户 PIN 码保护的加密密钥用于解锁设备和解密 CE 存储。
    • 当计划进行夜间重启时,Android 会提示用户输入其 PIN 码,然后计算合成密码 (SP)。
    • 然后,它使用存储在 RAM 中的密钥 K_s 和存储在 TEE 中的密钥 K_k 对 SP 进行两次加密。
    • 双重加密的 SP 存储在磁盘上,而 SP 从 RAM 中擦除。这两个密钥都是新生成的,并且仅用于一次重启
  • 当到重启时间时,Android 会将 K_s 委托给服务器。带有 K_k 的收据在存储到磁盘之前会被加密。
  • 重启后,Android 使用 K_k 解密收据,然后将其发送到服务器以检索 K_s
    • K_kK_s 用于解密存储在磁盘上的 SP。
    • Android 使用 SP 解锁 CE 存储并允许正常的应用启动。
    • K_kK_s 被丢弃。

使您的手机保持安全的更新可以在您方便的时候进行:在您睡觉时。

SIM 卡 PIN 码重放

在某些情况下,SIM 卡的 PIN 码会从缓存中验证,此过程称为 SIM 卡 PIN 码重放。

启用 PIN 码的 SIM 卡还必须在无人值守重启后进行无缝 PIN 码验证(SIM 卡 PIN 码重放),以恢复蜂窝网络连接(电话呼叫、短信和数据服务需要)。SIM 卡 PIN 码及其匹配的 SIM 卡信息(ICCID 和 SIM 卡插槽号)安全地存储在一起。存储的 PIN 码只能在成功进行无人值守重启后才能检索和用于验证。如果设备受到保护,则 SIM 卡 PIN 码与受 LSKF 保护的密钥一起存储。如果 SIM 卡启用了 PIN 码,则与 RoR 服务器的交互需要通过 WiFi 连接进行 OTA 更新和基于服务器的 RoR,这确保了重启后的基本功能(具有蜂窝网络连接)。

每次用户成功启用、验证或修改 SIM 卡 PIN 码时,SIM 卡 PIN 码都会被重新加密并存储。如果发生以下任何一种情况,SIM 卡 PIN 码将被丢弃

  • SIM 卡被移除或重置。
  • 用户禁用 PIN 码。
  • 发生了非 RoR 启动的重启。

存储的 SIM 卡 PIN 码只能在 RoR 启动的重启后使用一次,并且只能在很短的时间内(20 秒)使用 — 如果 SIM 卡的详细信息匹配。存储的 SIM 卡 PIN 码永远不会离开 TelephonyManager 应用,并且外部模块无法检索它。

实施指南

在 Android 12 中,多客户端和基于服务器的 RoR 功能在合作伙伴推送 OTA 更新时提供了更轻的负载。必要的更新可以在方便的设备停机期间发生,例如在指定的睡眠时间。

为了确保在此期间进行的 OTA 更新不会打扰用户,请采用暗模式来减轻光线辐射。为此,请让设备引导加载程序搜索字符串 reason unattended。如果 unattendedtrue,则将设备置于暗模式。请注意,减轻声音和光线辐射是每个 OEM 的责任。

如果您要升级到 Android 12 或发布 Android 12 设备,则无需执行任何操作即可实施新的 RoR 功能。

多客户端流程中有一个新的调用 isPreparedForUnattendedUpdate,如下所示

@RequiresPermission(anyOf = {android.Manifest.permission.RECOVERY,
            android.Manifest.permission.REBOOT})
public static boolean isPreparedForUnattendedUpdate(@NonNull Context context)

您无需实现此调用,因为 HAL 已在 Android 12 中弃用。

TelephonyManager

当 Android 12 中即将重启时,OTA 客户端会调用 TelephonyManager 系统 API。此 API 会将所有缓存的 PIN 码从 AVAILABLE 状态移动到 REBOOT_READY 状态。TelephonyManager 系统 API 受现有的 REBOOT Manifest 权限保护。

 /**
    * The unattended reboot was prepared successfully.
    * @hide
    */
   @SystemApi
   public static final int PREPARE_UNATTENDED_REBOOT_SUCCESS = 0;

   /**
    * The unattended reboot was prepared, but the user will need to manually
    * enter the PIN code of at least one SIM card present in the device.
    * @hide
    */
   @SystemApi
   public static final int PREPARE_UNATTENDED_REBOOT_PIN_REQUIRED = 1;

   /**
    * The unattended reboot was not prepared due to generic error.
    * @hide
    */
   @SystemApi
   public static final int PREPARE_UNATTENDED_REBOOT_ERROR = 2;

   /** @hide */
   @Retention(RetentionPolicy.SOURCE)
   @IntDef(prefix = {"PREPARE_UNATTENDED_REBOOT_"},
           value = {
                   PREPARE_UNATTENDED_REBOOT_SUCCESS,
                   PREPARE_UNATTENDED_REBOOT_PIN_REQUIRED,
                   PREPARE_UNATTENDED_REBOOT_ERROR
           })
   public @interface PrepareUnattendedRebootResult {}

   /**
    * Prepare TelephonyManager for an unattended reboot. The reboot is
    * required to be done shortly after the API is invoked.
    *
    * Requires system privileges.
    *
    * <p>Requires Permission:
    *   {@link android.Manifest.permission#REBOOT}
    *
    * @return {@link #PREPARE_UNATTENDED_REBOOT_SUCCESS} in case of success.
    * {@link #PREPARE_UNATTENDED_REBOOT_PIN_REQUIRED} if the device contains
    * at least one SIM card for which the user needs to manually enter the PIN
    * code after the reboot. {@link #PREPARE_UNATTENDED_REBOOT_ERROR} in case
    * of error.
    * @hide
    */
   @SystemApi
   @RequiresPermission(android.Manifest.permission.REBOOT)
   @PrepareUnattendedRebootResult
   public int prepareForUnattendedReboot()

TelephonyManager 系统 API 由特权 APK 使用。

测试

要测试新的 API,请执行以下命令

    adb shell cmd phone unattended-reboot

此命令仅在 shell 作为 root 用户运行时才有效 (adb root)。

仅限 Android 11

本页的其余部分适用于 Android 11。

截至 2020 年 7 月,RoR HAL 的实现分为两类

  1. 如果 SoC 硬件支持跨重启的 RAM 持久性,则 OEM 可以使用 AOSP 中的默认实现 (默认 RAM 托管)。
  2. 如果设备硬件或 SoC 支持安全硬件飞地(具有自己的 RAM 和 ROM 的独立安全协处理器),则此外还必须执行以下操作
    • 能够检测主 CPU 重启。
    • 具有跨重启持久存在的硬件计时器源。也就是说,飞地必须能够检测重启并使重启前设置的计时器过期。
    • 支持在飞地 RAM/ROM 中存储托管密钥,使其无法通过离线攻击恢复。它必须以使内部人员或攻击者无法恢复 RoR 密钥的方式存储 RoR 密钥。

默认 RAM 托管

AOSP 具有使用 RAM 持久性的 RoR HAL 实现。为了使其正常工作,OEM 必须确保其 SoC 支持跨重启的 RAM 持久性。某些 SoC 无法在重启后保持 RAM 内容持久,因此建议 OEM 在启用此默认 HAL 之前咨询其 SoC 合作伙伴。以下部分是此规范参考。

使用 RoR 的 OTA 更新流程

手机上的 OTA 客户端应用必须具有 Manifest.permission.REBOOTManifest.permission.RECOVERY 权限才能调用实现 RoR 所需的方法。在具备此先决条件的情况下,更新流程遵循以下步骤

  1. OTA 客户端应用下载更新。
  2. OTA 客户端应用调用 RecoverySystem#prepareForUnattendedUpdate,这将触发在下次解锁期间在锁屏上提示用户输入其 PIN 码、图案或密码。
  3. 用户在锁屏上解锁设备,设备已准备好应用更新。
  4. OTA 客户端应用调用 RecoverySystem#rebootAndApply,这将立即触发重启。

在此流程结束时,设备会重启,并且 RoR 机制会解锁凭据加密 (CE) 存储。对于应用而言,这表现为正常的用户解锁,因此它们会收到所有信号,例如 ACTION_LOCKED_BOOT_COMPLETEDACTION_BOOT_COMPLETED,就像正常情况下一样。

修改产品配置

在 Android 11 中标记为支持 RoR 功能的产品必须包含 RebootEscrow HAL 的实现,并包含功能标记 XML 文件。默认实现在使用热重启(重启期间 DRAM 的电源保持开启)的设备上运行良好。

重启托管功能标记

功能标记也必须存在

PRODUCT_COPY_FILES += \
    frameworks/native/data/etc/android.hardware.reboot_escrow.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.reboot_escrow.xml

默认重启托管 HAL 实现

要使用默认实现,您必须保留 65536 (0x10000) 字节。切勿将这些字节写入非易失性存储,以确保安全属性持久存在。

Linux 内核设备树更改

在 Linux 内核的设备树中,您必须为 pmem 区域保留内存。以下示例显示保留了 0x50000000

  reserved-memory {
    my_reservation@0x50000000 {
      no-map;
      reg = <0x50000000 0x10000>;
    }
  }

  reboot_escrow@0 {
    compatible = "pmem-region";
    reg = <0x50000000 0x10000>;
  };

验证您在块目录中是否有一个名为 /dev/block/pmem0(例如 pmem1pmem2)的新设备。

Device.mk 更改

假设您在上一步中的新设备名为 pmem0,您必须确保将以下新条目添加到 vendor/<oem>/<product>/device.mk

# Resume on Reboot support
PRODUCT_PROPERTY_OVERRIDES += \
    ro.rebootescrow.device=/dev/block/pmem0
PRODUCT_PACKAGES += \
    android.hardware.rebootescrow-service.default
SELinux 规则

将这些新条目添加到设备的 file_contexts

/dev/block/pmem0  u:object_r:rebootescrow_device:s0
/vendor/bin/hw/android\.hardware\.rebootescrow-service\.default  u:object_r:hal_rebootescrow_default_exec:s0