재부팅 시 다시 시작

Android 11에서는 A/B 업데이트 또는 가상 A/B 업데이트 메커니즘과 RecoverySystem 클래스 메서드를 사용하여 OTA 업데이트를 적용할 수 있습니다. 기기가 OTA 업데이트의 적용을 위해 재부팅하면 재부팅 시 다시 시작(RoR)이 기기의 사용자 인증 정보 암호화(CE) 저장소를 잠금 해제합니다.

Android 11에서는 이 프로세스를 기기가 유휴 상태일 것으로 예상되는 시점에 업데이트를 적용하는 OTA 시스템 기능과 함께 사용할 수 있는 반면, Android 12에서는 추가 OTA 시스템 기능이 필요하지 않습니다. RoR 프로세스는 기기 유휴 시간 동안 업데이트를 진행할 수 있고 Android 12의 멀티 클라이언트 기능과 서버 기반 업데이트 기능이 기기 하드웨어 수준 유형의 보안을 제공하기 때문에 사용자에게 향상된 보안과 편의성을 제공합니다.

Android 11에서 android.hardware.reboot_escrow 기능이 RoR을 지원하도록 하려면 기기에 권한을 제공해야 하는 반면 Android 12 이상에서는 HAL이 사용되지 않으므로 서버 기반 RoR을 사용 설정하기 위해 권한을 제공하지 않아도 됩니다.

android.hardware.reboot_escrow 기능이 RoR을 지원하도록 하려면 기기에 권한을 제공해야 합니다. Android 12 이상에서는 HAL이 사용되지 않으므로 서버 기반 RoR을 사용 설정하기 위해 아무것도 할 필요가 없습니다.

배경

Android는 사용자가 CE 저장소를 잠금 해제하기 전에 기기의 앱이 시작될 수 있도록 해 주는 직접 부팅을 Android 7부터 지원했습니다. 직접 부팅 지원을 구현하면 부팅 후 잠금 화면 지식 계수(LSKF)를 입력하기 전에 사용자에게 향상된 경험이 제공되었습니다.

RoR은 OTA 업데이트 후에 재부팅이 시작되었을 때 기기에서 직접 부팅을 지원하지 않는 앱을 포함하여 모든 앱의 CE 저장소가 잠금 해제될 수 있도록 해 줍니다. 이 기능을 사용하면 재부팅 후 모든 설치된 앱에서 알림을 받을 수 있습니다.

위협 모델

RoR 구현은 기기가 공격자의 손에 들어갔을 때, 기기가 켜져 있거나 CE 저장소가 잠금 해제되었거나 사용자가 OTA 업데이트를 받은 후 기기를 잠금 해제한 경우에도 공격자가 사용자의 CE 암호화 데이터를 복구하기 어렵게 해야 합니다. 공격자가 브로드캐스트 암호화 서명 키에 액세스할 수 있는 경우에도 내부자 공격 저항이 효과적으로 작동해야 합니다.

CE 저장소는 기기 실물을 갖고 있는 공격자가 읽을 수 없어야 하며, 다음과 같은 기능 및 제한사항을 갖습니다.

기능

  • 공급업체 또는 회사의 서명 키를 사용하여 임의의 메시지에 서명할 수 있습니다.
  • 기기가 OTA 업데이트를 수신하도록 할 수 있습니다.
  • 애플리케이션 프로세서, 플래시 메모리와 같은 하드웨어의 작동을 수정할 수 있습니다(아래의 제한사항에 나와 있는 경우 제외). (단, 이러한 수정이 이루어질 경우 최소 1시간의 지연이 발생하고 전원이 꺼졌다 켜져 RAM 콘텐츠가 소멸됩니다.)

제한사항

  • 변조 방지 하드웨어(예: Titan M)의 작동은 수정할 수 없습니다.
  • 라이브 기기의 RAM은 읽을 수 없습니다.
  • 사용자 인증 정보(PIN, 패턴, 비밀번호)를 추측하거나 그 밖의 방식으로 입력되도록 만들 수 없습니다.

해결 방법

Android 12의 RoR 업데이트 시스템은 수준 높은 공격자의 공격을 방어하며, 그 과정에서 기기 전용 비밀번호와 PIN은 기기에 유지되며 Google 서버에 전송되거나 저장되지 않습니다. 다음은 하드웨어 기반의 기기 수준 RoR 시스템과 유사한 보안 수준을 제공하는 프로세스에 관한 설명입니다.

  • Android가 기기에 저장된 데이터에 암호화 보호를 적용합니다.
  • 모든 데이터는 신뢰할 수 있는 실행 환경(TEE)에 저장된 키에 의해 보호됩니다.
  • TEE는 실행 중인 운영체제가 암호화 인증을 통과한 경우에만 키를 넘겨줍니다(자체 검사 부팅).
  • Google 서버에서 실행되는 RoR 서비스는 한시적으로만 가져올 수 있는 보안 비밀을 저장하여 CE 데이터를 보호합니다. 이는 Android 생태계 전반에 적용됩니다.
  • 기기를 잠금 해제하고 CE 저장소를 복호화하는 데 사용자의 PIN으로 보호되는 암호화 키가 사용됩니다.
    • 야간 재부팅이 예약된 경우, Android가 사용자에게 PIN을 입력하라고 요구한 다음 합성 비밀번호(SP)를 계산합니다.
    • 그런 다음 RAM에 저장된 K_s를 사용하여 한 번, TEE에 저장된 키 K_k를 사용하여 한 번, 이렇게 두 차례에 걸쳐 SP를 암호화합니다.
    • 이중 암호화된 SP는 디스크에 저장되고 RAM에서 완전 삭제됩니다. 두 키 모두 한 번의 재부팅에만 사용되며 매번 새로 생성됩니다.
  • 재부팅할 시점이 되면 Android가 서버에 K_s를 전송합니다. K_k를 갖는 수신은 암호화된 후에 디스크에 저장됩니다.
  • 재부팅이 완료되면 Android가 K_k를 사용하여 수신을 복호화한 다음 서버로 전송하여 K_s를 가져옵니다.
    • 디스크에 저장된 SP를 복호화하는 데 K_kK_s가 사용됩니다.
    • Android는 SP를 사용하여 CE 저장소를 잠금 해제하고 정상적인 앱 시작을 허용합니다.
    • K_kK_s가 삭제됩니다.

이처럼 휴대전화를 안전하게 지켜 주는 업데이트는 사용자가 잠을 자는 동안에 편리하게 진행될 수 있습니다.

SIM-PIN 리플레이

특정 조건에서는 SIM 카드의 PIN 코드가 캐시로부터 인증되는데, 이 프로세스를 SIM-PIN 리플레이라고 합니다.

사용 설정된 PIN이 있는 SIM 카드가 무인 재부팅 후에 (통화, SMS 메시지, 데이터 서비스에 필요한) 모바일 데이터 연결을 복원하려면 지연 없이 PIN 코드 인증(SIM-PIN 리플레이)을 거쳐야 합니다. SIM PIN과 관련 SIM 카드 정보(ICCID 및 SIM 슬롯 번호)는 안전하게 함께 저장됩니다. 저장된 PIN은 무인 재부팅이 성공적으로 완료된 후에만 가져와서 인증에 사용할 수 있습니다. 보호된 기기에서는 SIM PIN이 LSKF로 보호된 키를 사용하여 저장됩니다. SIM의 PIN이 사용 설정된 경우, RoR 서버와 상호작용하려면 OTA 업데이트와 서버 기반 RoR을 위해 WiFi 연결이 필요합니다. 이에 따라 재부팅 후에 모바일 데이터 연결을 통한 기본적인 기능이 보장됩니다.

SIM PIN은 사용자가 성공적으로 SIM PIN을 사용 설정하거나 인증하거나 수정할 때마다 다시 암호화되어 저장됩니다. SIM PIN은 다음 중 하나에 해당하는 경우 삭제됩니다.

  • SIM이 제거되거나 재설정되었습니다.
  • 사용자가 PIN을 사용 중지했습니다.
  • RoR가 아닌 다른 방식으로 시작된 재부팅이 발생했습니다.

저장된 SIM PIN은 RoR이 시작한 재부팅 후에 SIM 카드의 세부정보가 일치하는 경우에만 짧은 시간 동안(20초) 한 번만 사용할 수 있습니다. 저장된 SIM PIN은 어떤 경우에도 TelephonyManager 앱 외부로 유출되지 않으며, 외부 모듈이 가져갈 수 없습니다.

구현 가이드

Android 12의 멀티 클라이언트 기능과 서버 기반 RoR 기능은 OTA 업데이트를 푸시하는 파트너의 부하를 줄여 줍니다. 지정된 수면 시간과 같은 기기 다운타임 중에 필수 업데이트가 이루어질 수 있습니다.

이러한 시간에 이루어지는 OTA 업데이트가 사용자를 방해하지 않도록 하려면 어두운 모드를 사용하여 빛 방출을 최소화하세요. 이렇게 하려면 기기 부트로더가 문자열 이유 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)

Android 12부터는 HAL이 지원 중단되므로 이 호출을 구현할 필요가 없습니다.

TelephonyManager

Android 12에서는 재부팅이 임박한 경우 OTA 클라이언트가 TelephonyManager 시스템 API를 호출합니다. 이 API는 모든 캐싱된 PIN 코드를 AVAILABLE 상태에서 REBOOT_READY 상태로 이동합니다. TelephonyManager 시스템 API는 기존 REBOOT 매니페스트 권한으로 보호됩니다.

 /**
    * 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

이 명령어는 셸이 루트(adb root)로 실행 중인 경우에만 작동합니다.

Android 11만 해당

이 페이지의 나머지 부분은 Android 11에 적용됩니다.

2020년 7월 현재, RoR HAL 구현은 두 가지 카테고리로 나뉩니다.

  1. SoC 하드웨어가 여러 재부팅에 걸친 RAM 지속성을 지원하는 경우, OEM은 AOSP의 기본 구현(기본 RAM 에스크로)을 사용할 수 있습니다.
  2. 기기 하드웨어 또는 SoC가 보안 하드웨어 인클레이브(자체 RAM과 ROM을 갖는 개별 보안 보조 프로세서)를 지원하는 경우, 추가로 다음을 충족해야 합니다.
    • 기본 CPU 재부팅을 감지할 수 있습니다.
    • 재부팅 후에도 지속되는 하드웨어 타이머 소스가 있습니다. 즉, 인클레이브는 재부팅을 감지하여 재부팅 전에 설정된 타이머를 만료할 수 있어야 합니다.
    • 오프라인 공격을 통해 복구될 수 없도록 인클레이브 RAM/ROM에 에스크로된 키가 저장되도록 지원합니다. 내부자 또는 공격자가 키를 복구할 수 없도록 RoR 키를 저장해야 합니다.

기본 RAM 에스크로

AOSP에는 RAM 지속성을 사용하는 RoR HAL의 구현이 있습니다. 이를 위해서는 OEM이 SoC가 여러 재부팅에 걸쳐 RAM 지속성을 지원하도록 해야 합니다. 재부팅 후에 RAM 콘텐츠를 유지할 수 없는 SoC도 있으니 OEM은 이 기본 HAL을 사용 설정하기 전에 SoC 파트너에게 문의하시기 바랍니다. 다음 섹션에서 관련 표준 프로세스를 확인하세요.

RoR을 사용한 OTA 업데이트 흐름

휴대전화의 OTA 클라이언트 앱에는 RoR을 구현하는 데 필요한 메서드를 호출하는 Manifest.permission.REBOOTManifest.permission.RECOVERY 권한이 있어야 합니다. 이러한 전제조건이 충족된 경우의 업데이트 흐름은 다음과 같습니다.

  1. OTA 클라이언트 앱이 업데이트를 다운로드합니다.
  2. OTA 클라이언트 앱이 RecoverySystem#prepareForUnattendedUpdate를 호출하여 다음번 잠금 해제 시에 잠금 화면에 PIN, 패턴 또는 비밀번호를 입력하라는 메시지를 표시합니다.
  3. 사용자가 잠금 화면에서 기기를 잠금 해제하면 기기가 업데이트를 적용할 준비가 완료됩니다.
  4. OTA 클라이언트 앱 RecoverySystem#rebootAndApply를 호출하여 즉시 재부팅을 트리거합니다.

이 흐름의 끝나면 기기가 재부팅되고 RoR 메커니즘이 사용자 인증 정보 암호화(CE) 저장소를 잠금 해제합니다. 앱에는 이 잠금 해제가 일반 사용자 잠금 해제로 보이므로 ACTION_LOCKED_BOOT_COMPLETED, ACTION_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(pmem1 또는 pmem2)과 같은 이름을 갖는 새 기기가 있는지 확인하세요.

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