게이트키퍼 하위 시스템은 TEE(신뢰할 수 있는 실행 환경)에서 기기 패턴/비밀번호 인증을 실행합니다. 게이트키퍼는 하드웨어 지원 비밀 키를 사용하여 비밀번호를 등록하고 인증합니다. 또한 게이트키퍼는 연속으로 실패한 인증 시도를 제한하며 주어진 시간 제한 및 지정된 연속 실패 시도 횟수를 기준으로 요청 처리를 거부해야 합니다.
사용자가 비밀번호를 인증하면 게이트키퍼는 보안 구성요소에서만 사용할 수 있는 부팅별 HMAC 키로 서명된 인증 토큰을 내보내고 이 토큰은 하드웨어 지원 키 저장소로 전송됩니다. 즉, 게이트키퍼 인증 토큰은 인증 귀속 키 (예: 앱에서 생성한 키)를 앱에서 사용할 수 있음을 키 저장소에 알립니다.
아키텍처
게이트키퍼에는 세 가지 주요 구성요소가 포함됩니다.
gatekeeperd
(게이트키퍼 데몬) — Android의 C++ 바인더 서비스로,IGatekeeper
의 기본 공급업체별 구현을 기반으로IGateKeeperService
AIDL 인터페이스를 구현하는 플랫폼 독립 로직이 포함되어 있습니다.- 게이트키퍼 하드웨어 추상화 계층 (HAL) 서비스:
IGatekeeper
AIDL 인터페이스의 공급업체별 구현입니다. 이 HAL 서비스는 Android에서 실행되지만 핵심 Gatekeeper 기능은 보안 환경에서 실행되어야 하므로 일반적으로 Gatekeeper TA와 통신합니다. - 게이트키퍼 신뢰할 수 있는 애플리케이션 (TA): TEE에서 실행되고 실제 비밀번호 또는 패턴 확인을 실행하는 공급업체별 구현입니다.
LockSettingsService
는 바인더를 통해 Android OS의 gatekeeperd
데몬에 도달하는 요청을 보냅니다. 그러면 gatekeeperd
데몬은 IGatekeeper
HAL 서비스에 요청을 보내고, 이 요청은 TEE의 상응하는 Gatekeeper TA에 도달합니다.

그림 1. GateKeeper 인증과 관련된 높은 수준의 데이터 흐름
gatekeeperd
데몬은 Android 프레임워크 API에 HAL 액세스 권한을 부여하고 기기 인증을 키 저장소에 보고하는 과정에 참여합니다.
gatekeeperd
데몬은 자체 프로세스에서 실행되며 시스템 서버와는 별개입니다.
HAL 구현
gatekeeperd
데몬은 IGatekeeper
HAL을 사용하여 비밀번호 인증을 위해 기본 Gatekeeper TA와 상호작용합니다. Gatekeeper TA 구현으로 blob에 서명 (등록)하고 blob을 인증할 수 있어야 합니다. 모든 구현은 비밀번호 인증이 성공할 때마다 생성되는 인증 토큰 (HardwareAuthToken
)의 표준 형식을 준수해야 합니다. HardwareAuthToken
의 콘텐츠 및 시맨틱에 관한 자세한 내용은 HardwareAuthToken.aidl
정의를 참고하세요.
IGatekeeper
HAL의 공급업체 구현은 enroll
및 verify
함수를 구현해야 합니다.
enroll
메서드는 비밀번호 blob을 가져와서 서명한 다음 서명을 핸들로 반환합니다.enroll
호출에서 반환된 blob에는system/gatekeeper/include/gatekeeper/password_handle.h
에 표시된 구조가 있어야 합니다.verify
기능은 제공된 비밀번호로 생성된 서명을 비교하고 등록된 비밀번호 핸들과 일치하는지 확인해야 합니다.
등록 및 인증에 사용된 키는 변경하면 안 되며 기기가 부팅될 때마다 다시 도출할 수 있어야 합니다.
Trusty 및 기타 구현
Trusty 운영체제는 TEE 환경을 위한 Google의 오픈소스 신뢰 OS이며 게이트키퍼의 승인된 구현을 포함하고 있습니다. 그러나 TEE가 영구 하드웨어 지원 키 및 정지 상태에서 틱하는 안전한 단조 시계에 액세스할 수 있는 한 모든 TEE OS에서 게이트키퍼를 구현할 수 있습니다.
Trusty는 내부 IPC 시스템을 사용하여 KeyMint와 게이트키퍼의 Trusty 구현 (Trusty Gatekeeper) 간에 직접적으로 공유된 비밀 정보를 통신합니다. 이 공유 비밀 정보는 키 저장소로 전송된 인증 토큰을 서명하여 비밀번호 인증을 증명하기 위한 용도로 사용됩니다. Trusty 게이트키퍼는 사용 시마다 KeyMint에서 키를 요청하며, 값을 유지하거나 캐싱하지 않습니다. 구현은 보안을 위협하지 않는 선에서 이러한 비밀 정보를 자유롭게 공유할 수 있습니다.
비밀번호를 등록하고 인증하는 데 사용된 HMAC 키는 게이트키퍼에서만 파생 및 유지됩니다.
Android에서는 완료될 기기 전용 루틴을 추가하기만 하면 되는 일반적인 C++ 게이트키퍼 구현을 제공합니다. Trusty 구현은 이를 기반으로 합니다. TEE의 기기 전용 코드로 TEE 게이트키퍼를 구현하려면 system/gatekeeper/include/gatekeeper/gatekeeper.h
의 함수와 주석을 참고하세요. 규정을 준수하는 구현의 기본 책임은 다음과 같습니다.
IGatekeeper
HAL을 준수합니다.- 반환된 인증 토큰은
HardwareAuthToken
사양 (HardwareAuthToken.aidl
에서 설명됨)에 따라 형식이 지정되어야 합니다. - TEE 게이트키퍼는 다음 중 하나를 사용하여 HMAC 키를 KeyMint와 공유할 수 있어야 합니다.
- 공유 비밀 계약: Gatekeeper는
ISharedSecret
HAL을 구현하여 HMAC 키의 부팅별 협상에 참여할 수 있습니다. 이를 위해서는 Gatekeeper와 KeyMint 모두 공통 사전 공유 비밀번호에 액세스할 수 있어야 합니다. - 직접 액세스: 게이트키퍼는 TEE 내부 프로세스 간 통신 메커니즘을 사용하여 KeyMint에서 HMAC 키를 요청 시 또는 처음 사용할 때 가져올 수 있습니다 (이후 캐시됨).
- 공유 비밀 계약: Gatekeeper는
사용자 보안 ID (SID)
사용자 SID는 사용자의 TEE 표현으로, Android 사용자 ID에 대한 연관성은 낮습니다. SID는 사용자가 이전 비밀번호를 제공하지 않은 상태에서 새 비밀번호를 등록할 때마다 PRNG(Pseudorandom Number Generator)를 사용하여 생성됩니다. 이를 신뢰할 수 없는 재등록이라 부르며, 일반적으로 사용자가 처음 비밀번호나 패턴을 설정할 때만 발생합니다.
신뢰할 수 있는 재등록은 사용자가 유효한 이전 비밀번호를 제공하는 경우에 발생합니다(예: 비밀번호 변경 시). 이 경우 사용자 SID는 새 비밀번호 핸들로 이전되어 여기에 바인드된 키를 보존합니다.
비밀번호가 등록되면 사용자 SID는 비밀번호 핸들의 비밀번호와 함께 HMAC 인증에 포함됩니다.
사용자 SID는 verify()
함수에 의해 반환된 HardwareAuthToken
에 포함되며 모든 인증 바인드 키 저장소 키에 연결됩니다. HardwareAuthToken
형식 및 키 저장소에 관한 자세한 내용은 인증을 참고하세요.
enroll()
함수에 대한 신뢰할 수 없는 호출은 사용자 SID를 변경하므로 호출로 인해 그 비밀번호에 바인드된 키가 쓸모없게 됩니다. 공격자는 Android OS를 제어하는 경우 기기 비밀번호를 변경할 수 있지만 이 과정에서 루트로 보호되는 민감한 키가 제거됩니다.
요청 제한
게이트키퍼는 사용자 인증 정보에 관한 무차별 공격 시도를 안전하게 제한할 수 있어야 합니다. GatekeeperVerifyResponse.aidl
에 표시된 것처럼 HAL은 밀리초 단위의 시간 제한을 반환할 수 있게 해줍니다. 시간 제한은 시간 제한이 경과될 때까지 게이트키퍼를 다시 호출하지 말라고 클라이언트에게 알립니다.
게이트키퍼는 시간 제한이 대기 중인 경우 요청을 처리하면 안 됩니다.
게이트키퍼는 사용자 비밀번호를 인증하기 전에 실패 카운터를 작성해야 합니다. 비밀번호 인증에 성공하면 실패 카운터가 삭제됩니다. 이렇게 하면 verify
호출 후에 삽입된 MMC(eMMC)를 사용 중지하여 제한을 방지하는 공격을 예방할 수 있습니다. enroll
기능 역시 사용자 비밀번호를 인증하며(제공된 경우) 같은 방식으로 제한되어야 합니다.
기기에서 지원하는 경우 실패 카운터를 보안 저장소에 작성하는 것이 좋습니다. 기기에서 파일 기반 암호화를 지원하지 않거나 보안 저장소가 너무 느린 경우 구현에서 RPMB(Replay Protected Memory Block)를 직접 사용할 수 있습니다.