하드웨어 지원 키 저장소

단일 칩 시스템(SoC)에서 신뢰할 수 있는 실행 환경이 제공되면 Android 기기에서 Android OS와 플랫폼 서비스에는 물론 서드 파티 앱에도 강력한 보안의 하드웨어 지원 서비스를 제공할 수 있습니다 (표준 Java 암호화 아키텍처에 대한 Android별 확장 프로그램 형식, KeyGenParameterSpec 참고).

용어집

다음은 키 저장소 구성요소와 그 관계에 관한 간단한 개요입니다.

AndroidKeyStore
앱에서 키 저장소 기능에 액세스하는 데 사용하는 Android Framework API 및 구성요소입니다. 이는 표준 Java Cryptography Architecture API의 구현이지만 Android용 확장 프로그램을 추가하고 앱의 자체 프로세스 공간에서 실행되는 Java 코드로 구성됩니다. AndroidKeyStore는 키 저장소 데몬으로 전달하여 키 저장소 동작에 관한 앱 요청을 처리합니다.
키 저장소 데몬
Binder API를 통해 모든 키 저장소 기능에 대한 액세스를 제공하는 Android 시스템 데몬입니다. 이 데몬은 기본 KeyMint (또는 Keymaster) 구현에서 생성된 키 blob을 저장합니다. 이 키 blob에는 비밀 키 자료가 포함되어 있으며 암호화되어 있으므로 키 저장소에서 저장할 수는 있지만 사용하거나 공개할 수는 없습니다.
KeyMint HAL 서비스
기본 KeyMint TA에 대한 액세스를 제공하는 IKeyMintDevice HAL을 구현하는 AIDL 서버입니다.
KeyMint 신뢰할 수 있는 앱 (TA)
안전한 암호화 작업을 모두 제공하는 소프트웨어로, 안전한 환경(대부분 ARM SoC의 TrustZone)에서 실행됩니다. 이 앱은 원시 키 재료에 액세스할 수 있으며 키 사용을 허용하기 전에 키의 모든 액세스 제어 조건을 검증합니다.
LockSettingsService
사용자 인증(비밀번호와 지문 모두)을 담당하는 Android 시스템 구성요소입니다. 이는 키 저장소의 일부가 아니지만 키 저장소에서 인증 바인딩 키 개념을 지원하므로(사용자가 인증한 경우에만 사용할 수 있는 키) 관련이 있습니다. LockSettingsService는 Gatekeeper TA 및 Fingerprint TA와 상호작용하여 인증 토큰을 가져와서 키 저장소 데몬에 제공합니다. 인증 토큰은 KeyMint TA에서 소비합니다.
게이트키퍼 TA
보안 환경에서 실행되며 사용자 비밀번호를 인증하고 특정 시점에 특정 사용자에 대해 인증이 완료되었음을 KeyMint TA에 증명하는 데 사용되는 인증 토큰을 생성하는 구성요소입니다.
지문 TA
보안 환경에서 실행되며 사용자 지문을 인증하고 특정 시점에 특정 사용자에 대해 인증이 완료되었음을 KeyMint TA에 증명하는 데 사용되는 인증 토큰을 생성하는 구성요소입니다.

아키텍처

Android Keystore API 및 기본 KeyMint HAL은 액세스가 제어된 하드웨어 지원 키를 사용하여 프로토콜을 구현할 수 있도록 기본적이지만 적절한 암호화 프리미티브 집합을 제공합니다.

KeyMint HAL은 키 저장소 서비스에서 하드웨어 지원 암호화 서비스를 제공하기 위해 사용하는 OEM 제공 서비스입니다. 비공개 키 자료를 안전하게 보호하기 위해 HAL 구현은 사용자 공간이나 커널 공간에서 민감한 작업을 실행하지 않습니다. 대신 Android에서 실행되는 KeyMint HAL 서비스는 일반적으로 구현 정의된 전송 형식에서 요청을 마샬링 및 마운설링하여 일종의 보안 환경에서 실행되는 TA에 민감한 작업을 위임합니다.

그 결과 생성되는 아키텍처는 다음과 같습니다.

KeyMint에 액세스

그림 1. KeyMint에 액세스합니다.

KeyMint HAL API는 하위 수준이며 플랫폼 내부 구성요소에서 사용되고 앱 개발자에게 노출되지 않습니다. 앱에서 사용할 수 있는 상위 수준 Java API는 Android 개발자 사이트에 설명되어 있습니다.

액세스 제어

Android 키 저장소는 앱과 기타 시스템 구성요소 모두에 대해 하드웨어 지원 암호화 키를 저장하고 사용하는 중앙 구성요소를 제공합니다. 따라서 개별 키에 대한 액세스는 일반적으로 키를 만든 앱 또는 시스템 구성요소로 제한됩니다.

키 저장소 도메인

이 액세스 제어를 지원하기 위해 키는 키 설명자를 사용하여 키 저장소에 식별됩니다. 이 키 설명자는 설명자가 속한 도메인과 해당 도메인 내의 ID를 나타냅니다.

Android 앱은 문자열 별칭으로 키를 식별하는 표준 Java Cryptography Architecture를 사용하여 키 저장소에 액세스합니다. 이 식별 방법은 내부적으로 키 저장소 APP 도메인에 매핑됩니다. 호출자의 UID도 포함되어 있어 서로 다른 앱의 키를 구분하여 한 앱이 다른 앱의 키에 액세스하는 것을 방지합니다.

내부적으로 프레임워크 코드는 키가 로드된 후 고유한 숫자 키 ID도 수신합니다. 이 숫자 ID는 KEY_ID 도메인 내 키 설명자의 식별자로 사용됩니다. 하지만 액세스 제어는 계속 실행됩니다. 한 앱이 다른 앱 키의 키 ID를 발견하더라도 일반적인 상황에서는 이를 사용할 수 없습니다.

그러나 앱이 다른 앱(UID로 식별됨)에 키 사용을 부여할 수는 있습니다. 이 부여 작업은 GRANT 도메인 내 키 설명자의 식별자로 사용되는 고유한 부여 식별자를 반환합니다. 다시 말하지만 액세스 제어는 계속 실행됩니다. 서드 파티 앱이 수혜자의 키에 대한 부여 ID를 발견하더라도 이를 사용할 수는 없습니다.

키 저장소는 키 설명자에 관한 다른 두 가지 도메인도 지원합니다. 이 도메인은 다른 시스템 구성요소에 사용되며 앱에서 생성한 키에는 사용할 수 없습니다.

  • BLOB 도메인은 키 설명자에 키 식별자가 없음을 나타냅니다. 대신 키 설명자가 키 blob 자체를 보유하고 클라이언트가 키 blob 저장소를 처리합니다. 데이터 파티션이 마운트되기 전에 키 저장소에 액세스해야 하는 클라이언트 (예: vold)에서 사용합니다.
  • SELINUX 도메인을 사용하면 시스템 구성요소가 SELinux 라벨에 해당하는 숫자 식별자로 제어되는 액세스 권한으로 키를 공유할 수 있습니다 (keystore_key의 SELinux 정책 참고).

keystore_key의 SELinux 정책

Domain::SELINUX 키 설명자에 사용되는 식별자 값은 keystore2_key_context SELinux 정책 파일에 구성됩니다. 이러한 파일의 각 줄은 숫자를 SELinux 라벨에 매핑합니다. 예를 들면 다음과 같습니다.

# wifi_key is a keystore2_key namespace intended to be used by wpa supplicant and
# Settings to share keystore keys.
102            u:object_r:wifi_key:s0

SELINUX 도메인에서 ID가 102인 키에 액세스해야 하는 구성요소에는 상응하는 SELinux 정책이 있어야 합니다. 예를 들어 wpa_supplicant가 이러한 키를 가져오고 사용하도록 허용하려면 hal_wifi_supplicant.te에 다음 줄을 추가합니다.

allow hal_wifi_supplicant wifi_key:keystore2_key { get, use };

Domain::SELINUX 키의 숫자 식별자는 충돌 없이 여러 파티션을 지원하기 위해 범위로 나뉩니다.

파티션 범위 구성 파일
시스템 0 ... 9,999 /system/etc/selinux/keystore2_key_contexts, /plat_keystore2_key_contexts
확장 시스템 10,000 ... 19,999 /system_ext/etc/selinux/system_ext_keystore2_key_contexts, /system_ext_keystore2_key_contexts
제품 20,000 ... 29,999 /product/etc/selinux/product_keystore2_key_contexts, /product_keystore2_key_contexts
공급업체 30,000 ... 39,999 /vendor/etc/selinux/vendor_keystore2_key_contexts, /vendor_keystore2_key_contexts

시스템 파티션에는 다음과 같은 특정 값이 정의되었습니다.

네임스페이스 ID SEPolicy 라벨 UID 설명
0 su_key 해당 사항 없음 슈퍼 사용자 키. userdebug 빌드와 eng 빌드 테스트에만 사용됩니다. 사용자 빌드와는 관련이 없습니다.
1 shell_key 해당 사항 없음 셸에 사용할 수 있는 네임스페이스입니다. 주로 테스트에 사용되지만, 명령줄을 통해 사용자 빌드에도 사용할 수 있습니다.
100 vold_key 해당 사항 없음 vold에서 사용하기 위한 용도입니다.
101 odsign_key 해당 사항 없음 기기 내 서명 데몬에 사용됩니다.
102 wifi_key AID_WIFI(1010) wpa_supplicant를 포함한 Android Wi-Fi 하위 시스템에서 사용합니다.
103 locksettings_key 해당 사항 없음 LockSettingsService에서 사용
120 resume_on_reboot_key AID_SYSTEM(1000) 재부팅 시 다시 시작을 지원하기 위해 Android 시스템 서버에서 사용합니다.

액세스 벡터

키 저장소를 사용하면 키에 대한 전반적인 액세스를 제어하는 것 외에도 키에 대해 실행할 수 있는 작업을 제어할 수 있습니다. keystore2_key 권한은 KeyPermission.aidl 파일에 설명되어 있습니다.

시스템 권한

keystore_key의 SELinux 정책에 설명된 키별 액세스 제어 외에도 다음 표에는 다양한 시스템 및 유지보수 작업을 실행하는 데 필요한 기타 SELinux 권한이 설명되어 있습니다.

권한 의미
add_auth 키 저장소에 인증 토큰을 추가하는 데 필요합니다. Gatekeeper 또는 BiometricManager와 같은 인증 제공업체에서 사용합니다.
clear_ns 특정 네임스페이스의 모든 키를 삭제하는 데 필요합니다. 앱이 제거될 때 유지보수 작업으로 사용됩니다.
list 시스템에서 소유권 또는 인증 제한 여부와 같은 다양한 속성별로 키를 열거하려면 필요합니다. 호출자가 자체 네임스페이스를 열거하는 경우에는 이 권한이 필요하지 않습니다 (get_info 권한에 포함됨).
lock 키 저장소에 기기가 잠겼음을 알리는 데 필요합니다. 그러면 수퍼 키가 제거되어 인증이 결합된 키를 사용할 수 없게 됩니다.
unlock 키 저장소에 기기가 잠금 해제되었음을 알리고 인증 결합 키를 보호하는 슈퍼 키에 대한 액세스 권한을 복원하는 데 필요합니다.
reset 키 저장소를 초기화하여 Android OS의 작동에 중요하지 않은 모든 키를 삭제하는 데 필요합니다.

기록

Android 5 이하에서는 Keymaster 하드웨어 추상화 계층 (HAL)의 0.2 및 0.3 버전에서 제공하는 단순한 하드웨어 지원 암호화 서비스 API가 있었습니다. 키 저장소는 디지털 서명 및 확인 작업 외에 비대칭 서명 키 쌍 생성 및 가져오기도 제공했습니다. 이는 이미 여러 기기에서 구현되었지만 서명 API만으로는 쉽게 달성할 수 없는 보안 목표가 많습니다. Android 6.0은 Keystore API를 확장하여 더 광범위한 기능을 제공합니다.

Android 6.0

Android 6.0에서 Keymaster 1.0은 대칭 암호화 프리미티브, AES 및 HMAC, 하드웨어 지원 키의 액세스 제어 시스템을 추가했습니다. 액세스 제어는 키 생성 중에 지정되며 키의 전체 기간에 시행됩니다. 사용자가 인증된 후에만, 그리고 지정된 목적을 위해 또는 지정된 암호화 매개변수와 함께인 경우에만 사용할 수 있도록 키를 제한할 수 있습니다.

Android 6.0의 키 저장소는 암호화 프리미티브의 범위 확장 외에 다음과 같은 이점도 제공합니다.

  • 키 사용을 제한할 수 있고 키의 오용으로 인한 보안 침해의 위험을 완화할 수 있는 사용 제어 체계
  • 지정된 사용자, 클라이언트, 정의된 시간 범위로 키 사용을 제한하기 위한 액세스 제어 체계

Android 7.0

Android 7.0에서 Keymaster 2는 키 증명 및 버전 결합을 추가로 지원했습니다.

키를 안전한 하드웨어에 저장하고 키 구성을 원격으로 확인할 수 있도록 키 증명은 자세한 키 설명과 액세스 제어를 포함하는 공개키 인증서를 제공합니다.

버전 결합은 키를 운영체제 및 패치 수준 버전에 결합합니다. 이렇게 하면 시스템 또는 TEE 소프트웨어의 이전 버전에서 취약성을 발견한 공격자가 기기를 취약한 버전으로 롤백하거나 최신 버전으로 만든 키를 사용할 수 없습니다. 또한 지정된 버전 및 패치 수준의 키가 최신 버전 또는 패치 수준으로 업그레이드된 기기에서 사용되면 이 키는 업그레이드된 후 사용되며 이전 버전의 키는 무효화됩니다. 기기가 업그레이드되면 기기와 함께 키가 업그레이드되지만 기기를 이전 버전으로 되돌리면 키를 사용할 수 없게 됩니다.

Android 8.0

Android 8.0에서 Keymaster 3은 이전 스타일의 C 구조 HAL로부터 새 하드웨어 인터페이스 정의 언어 (HIDL)의 정의에서 생성된 C++ HAL 인터페이스로 전환되었습니다. 변경사항의 일부로 많은 인수 유형이 변경되었지만 유형과 메서드는 이전 유형 및 HAL 구조 메서드와 일대일로 대응합니다.

이 인터페이스 개정 외에도 Android 8.0은 ID 증명을 지원하기 위해 Keymaster 2의 증명 기능을 확장했습니다. ID 증명은 기기 일련번호, 제품 이름, 스마트폰 ID (IMEI 또는 MEID)와 같은 하드웨어 식별자를 엄격하게 증명하기 위한 제한적이고 선택적인 메커니즘을 제공합니다. 이 추가 기능을 구현하기 위해 Android 8.0은 ID 증명을 추가하도록 ASN.1 증명 스키마를 변경했습니다. Keymaster를 구현하려면 영구적으로 안전하게 기능을 사용 중지하는 메커니즘을 정의하는 것뿐만 아니라 관련 데이터 항목을 검색하는 안전한 방법을 찾아야 합니다.

Android 9

Android 9의 업데이트에는 다음이 포함됩니다.

  • Keymaster 4로 업데이트
  • 삽입된 보안 요소 지원
  • 보안 키 가져오기 지원
  • 3DES 암호화 지원
  • 독립된 업데이트를 허용하기 위해 boot.imgsystem.img에 별도로 설정된 버전이 포함되도록 버전 결합 변경

Android 10

Android 10에서는 다음을 추가한 Keymaster HAL 버전 4.1을 도입했습니다.

  • 기기가 잠금 해제된 경우에만 사용할 수 있는 키 지원
  • 초기 부팅 단계에서만 사용할 수 있는 키 지원
  • 하드웨어 래핑 스토리지 키 지원(선택사항)
  • StrongBox에서 기기 고유 증명 지원(선택사항)

Android 12

Android 12에서는 Keymaster HAL을 대체하지만 유사한 기능을 제공하는 새로운 KeyMint HAL을 도입했습니다. 위의 모든 기능 외에도 KeyMint HAL에는 다음이 포함됩니다.

  • ECDH 키 협약 지원
  • 사용자 지정 증명 키 지원
  • 사용 횟수가 제한된 키 지원

Android 12에는 Rust로 재작성되고 keystore2라고 하는 새 버전의 키 저장소 시스템 데몬도 포함되어 있습니다.

Android 13

Android 13에서는 서명 및 키 계약 모두에 Curve25519 지원을 추가하는 KeyMint HAL v2를 추가했습니다.