버전 결합

Keymaster 1에서 모든 keymaster 키는 신뢰할 수 있는 루트 기기 또는 자체 검사 부팅 키에 암호화 방식으로 결합되었습니다. Keymaster 2와 3에서는 모든 키가 시스템 이미지의 운영체제와 패치 수준에도 결합됩니다. 이렇게 하면 시스템 또는 TEE 소프트웨어의 이전 버전에서 취약성을 발견한 공격자가 기기를 취약한 버전으로 롤백하거나 최신 버전으로 만든 키를 사용할 수 없습니다. 또한 지정된 버전 및 패치 수준의 키가 최신 버전 또는 패치 수준으로 업그레이드된 기기에서 사용되면 이 키는 업그레이드된 후 사용되며 이전 버전의 키는 무효화됩니다. 이렇게 해서 기기가 업그레이드되면 키가 기기와 함께 업그레이드되며 기기를 이전 버전으로 되돌리면 키를 사용할 수 없게 됩니다.

Keymaster 4에서는 Treble의 모듈형 구조를 지원하고 system.img와 boot.img의 결합을 깨기 위해 키 버전 결합 모델을 변경하여 각 파티션에 별도의 패치 수준이 있도록 했습니다. 이렇게 하면 롤백을 방지하면서 각 파티션을 독립적으로 업데이트할 수 있습니다.

Android 9에서 boot, systemvendor 파티션에는 각각 고유한 패치 수준이 있습니다.

  • Android 자체 검사 부팅(AVB)이 포함된 기기는 모든 패치 수준과 시스템 버전을 vbmeta에 넣을 수 있으므로 부트로더가 이러한 패치 수준과 시스템 버전을 Keymaster에 제공할 수 있습니다. 연결된 파티션의 경우 파티션의 버전 정보는 연결된 vbmeta에 저장됩니다. 일반적으로 버전 정보는 지정된 파티션의 검증 데이터(해시 또는 해시트리)를 포함하는 vbmeta struct에 있어야 합니다.
  • AVB가 없는 기기:
    • 자체 검사 부팅 구현은 부트로더가 Keymaster에 해시를 제공할 수 있도록 버전 메타데이터의 해시를 부트로더에 제공해야 합니다.
    • boot.img는 패치 수준을 헤더에 계속해서 저장할 수 있습니다.
    • system.img는 패치 수준 및 OS 버전을 읽기 전용 속성에 계속해서 저장할 수 있습니다.
    • vendor.img는 읽기 전용 속성 ro.vendor.build.version.security_patch에 패치 수준을 저장합니다.
    • 부트로더는 자체 검사 부팅으로 확인된 모든 데이터의 해시를 keymaster에 제공할 수 있습니다.
  • Android 9에서는 다음 태그를 사용하여 다음 파티션의 버전 정보를 제공합니다.
    • VENDOR_PATCH_LEVEL: vendor 파티션
    • BOOT_PATCH_LEVEL: boot 파티션
    • OS_PATCH_LEVELOS_VERSION: system 파티션. (OS_VERSIONboot.img 헤더에서 삭제됩니다.)
  • Keymaster 구현은 모든 패치 수준을 독립적으로 취급해야 합니다. 모든 버전 정보가 키와 연결된 값과 일치하면 키를 사용할 수 있고 필요한 경우 IKeymaster::upgradeDevice()는 더 높은 패치 수준으로 롤업합니다.

HAL 변경사항

버전 결합 및 버전 증명을 지원하기 위해 Android 7.1에서는 Tag::OS_VERSIONTag::OS_PATCHLEVEL 태그와 configureupgradeKey 메서드를 추가했습니다. 새로 생성되거나 업데이트된 모든 키에 Keymaster 2 이상의 구현에 의해 버전 태그가 자동으로 추가됩니다. 또한 OS 버전이나 패치 수준이 현재 시스템 OS 버전 또는 패치 수준과 일치하지 않는 키를 사용하려고 하면 ErrorCode::KEY_REQUIRES_UPGRADE와 함께 거부됩니다.

Tag::OS_VERSION은 Android 시스템의 주 버전, 부 버전 및 하위 부 버전 부분을 MMmmss로 나타내는 UINT 값입니다. 여기서 MM은 주 버전 번호이고 mm은 부 버전 번호이며 ss는 하위 부 버전 번호입니다. 예를 들어 6.1.2는 060102로 표시됩니다.

Tag::OS_PATCHLEVEL은 시스템을 마지막으로 업데이트한 연도와 월을 YYYYMM으로 나타내는 UINT 값입니다. 여기서 YYYY는 네 자리 숫자 연도이고 MM은 두 자리 숫자 월입니다. 예를 들어 2016년 3월은 201603으로 표시됩니다.

UpgradeKey

키를 시스템 이미지의 새 OS 버전 및 패치 수준으로 업그레이드할 수 있도록 Android 7.1에서는 upgradeKey 메서드가 HAL에 추가되었습니다.

Keymaster 3

    upgradeKey(vec keyBlobToUpgrade, vec upgradeParams)
        generates(ErrorCode error, vec upgradedKeyBlob);

Keymaster 2

keymaster_error_t (*upgrade_key)(const struct keymaster2_device* dev,
    const keymaster_key_blob_t* key_to_upgrade,
    const keymaster_key_param_set_t* upgrade_params,
    keymaster_key_blob_t* upgraded_key);
  • dev는 기기 구조입니다.
  • keyBlobToUpgrade는 업그레이드해야 하는 키입니다.
  • upgradeParams는 키를 업그레이드하는 데 필요한 매개변수입니다. 여기에는 키 blob을 복호화하는 데 필요한 Tag::APPLICATION_IDTag::APPLICATION_DATA가 생성 중 제공된 경우 포함됩니다.
  • upgradedKeyBlob은 새 키 blob을 반환하는 데 사용되는 출력 매개변수입니다.

파싱할 수 없거나 유효하지 않은 키 blob으로 upgradeKey를 호출하면 ErrorCode::INVALID_KEY_BLOB이 반환됩니다. 패치 수준이 현재 시스템 값보다 큰 키를 사용하여 호출하면 ErrorCode::INVALID_ARGUMENT가 반환됩니다. OS 버전이 현재 시스템 값보다 큰 키를 사용하여 호출하고 시스템 값이 0이 아니면 ErrorCode::INVALID_ARGUMENT가 반환됩니다. 0이 아닌 값에서 0으로의 OS 버전 업그레이드가 허용됩니다. 안전한 환경과의 통신에 오류가 발생하면 적절한 오류 값이 반환됩니다(예: ErrorCode::SECURE_HW_ACCESS_DENIED, ErrorCode::SECURE_HW_BUSY). 아니면 ErrorCode::OK가 반환되고 upgradedKeyBlob에서 새 키 blob이 반환됩니다.

keyBlobToUpgradeupgradeKey 호출 후에도 유효하며 기기가 다운그레이드된 경우 이론적으로 다시 사용할 수 있습니다. 실제로 키 저장소는 일반적으로 upgradeKey를 호출한 직후 keyBlobToUpgrade blob에서 deleteKey를 호출합니다. keyBlobToUpgradeTag::ROLLBACK_RESISTANT 태그가 있는 경우 upgradedKeyBlob에도 있어야 합니다(또한 롤백이 방지되어야 함).

안전한 구성

버전 결합을 구현하기 위해 keymaster TA는 현재 OS 버전 및 패치 수준(버전 정보)을 안전하게 수신해야 하며, 수신하는 정보가 실행 중인 시스템에 관한 정보와 정확히 일치하는지 확인해야 합니다.

TA에 버전 정보를 안전하게 전송하도록 지원하기 위해 OS_VERSION 필드가 부팅 이미지 헤더에 추가되었습니다. 부팅 이미지 빌드 스크립트가 자동으로 이 필드를 채웁니다. 안전하지 않은 시스템이 부팅되기 전에 부팅 이미지에서 버전 정보를 추출하여 TA로 전달하기 위해 OEM과 Keymaster TA 구현자는 협력을 통해 기기 부트로더를 수정해야 합니다. 이렇게 하면 버전 정보를 TA에 프로비저닝하는 작업을 공격자가 방해할 수 없습니다.

또한 시스템 이미지와 부팅 이미지의 버전 정보가 동일한지 확인해야 합니다. 이를 위해 configure 메서드가 keymaster HAL에 추가되었습니다.

keymaster_error_t (*configure)(const struct keymaster2_device* dev,
  const keymaster_key_param_set_t* params);

params 인수는 Tag::OS_VERSIONTag::OS_PATCHLEVEL을 포함합니다. 이 메서드는 HAL을 연 다음 다른 메서드를 호출하기 전에 keymaster2 클라이언트에 의해 호출됩니다. configure가 호출되기 전에 다른 메서드가 호출되면 TA는 ErrorCode::KEYMASTER_NOT_CONFIGURED를 반환합니다.

configure는 기기 부팅 이후 처음 호출되면 제공된 버전 정보가 부트로더에서 제공한 버전 정보와 일치하는지 확인해야 합니다. 버전 정보가 일치하지 않으면 configureErrorCode::INVALID_ARGUMENT를 반환하며 다른 모든 keymaster 메서드는 계속해서 ErrorCode::KEYMASTER_NOT_CONFIGURED를 반환합니다. 정보가 일치하면 configureErrorCode::OK를 반환하며 다른 keymaster 메서드는 정상적으로 작동하기 시작합니다.

이후 configure를 호출하면 첫 번째 호출에서 반환된 것과 동일한 값이 반환되며 keymaster의 상태가 변경되지 않습니다. 이 프로세스를 진행하려면 모든 OTA 업데이트가 시스템 이미지와 부팅 이미지를 모두 업데이트해야 합니다. 이러한 이미지는 버전 정보 동기화를 위해 별도로 업데이트할 수 없습니다.

콘텐츠의 유효성을 검사하려는 시스템에서 configure를 호출하게 되므로 공격자가 시스템 이미지를 손상시켜 부팅 이미지와 일치하는 버전 정보(그러나 실제 시스템 버전이 아닌 정보)를 강제로 제공하도록 할 가능성이 적습니다. 부팅 이미지 확인 및 시스템 이미지 콘텐츠의 dm-verity 유효성 검사가 실행되고 시스템 부팅 초기에 configure가 호출되므로 공격자가 이러한 기회를 악용하기 어렵습니다.