게이트키퍼

게이트키퍼 하위 시스템은 TEE(신뢰할 수 있는 실행 환경)에서 기기 패턴/비밀번호 인증을 실행합니다. 게이트키퍼는 하드웨어 지원 비밀 키가 포함된 HMAC를 통해 비밀번호를 등록하고 인증합니다. 또한 게이트키퍼는 연속으로 실패한 인증 시도를 제한하며 주어진 시간 제한 및 지정된 연속 실패 시도 횟수를 기준으로 요청 처리를 거부해야 합니다.

사용자가 비밀번호를 인증하면 게이트키퍼는 TEE에서 파생된 공유 비밀번호를 사용하여 인증 증명에 서명하고 하드웨어 지원 키 저장소로 전송합니다. 즉, 게이트키퍼 인증은 앱에서 사용할 수 있도록 인증 귀속 키(예: 앱에서 생성한 키)를 공개할 수 있음을 키 저장소에 알립니다.

아키텍처

게이트키퍼에는 세 가지 주요 구성요소가 포함됩니다.

  • gatekeeperd(게이트키퍼 데몬). GateKeeperService 자바 인터페이스에 상응하고 플랫폼 독립 로직이 포함되어 있는 C++ 바인더 서비스입니다.
  • 게이트키퍼 HAL(하드웨어 추상화 계층). hardware/libhardware/include/hardware/gatekeeper.h의 HAL 인터페이스 및 구현 모듈입니다.
  • 게이트키퍼(TEE). gatekeeperd의 TEE 상응 요소입니다. 게이트키퍼의 TEE 기반 구현입니다.

게이트키퍼에는 게이트키퍼 HAL(구체적으로 hardware/libhardware/include/hardware/gatekeeper.h의 기능)과 TEE 전용 게이트키퍼 구성요소(키 만들기/액세스 및 서명 계산을 위한 순수 가상 기능이 포함된 system/gatekeeper/include/gatekeeper/gatekeeper.h 헤더 파일에 일부 기반함)의 구현이 필요합니다.

LockSettingsService는 바인더를 통해 Android OS의 gatekeeperd 데몬에 도달하는 요청을 보냅니다. 그러면 gatekeeperd 데몬은 TEE의 상응 요소(게이트키퍼)에 도달하는 요청을 보냅니다.

게이트키퍼 흐름
그림 1. 게이트키퍼 인증과 관련된 높은 수준의 데이터 흐름

gatekeeperd 데몬은 Android 프레임워크 API에 HAL 액세스 권한을 부여하고 기기 인증을 키 저장소에 보고하는 과정에 참여합니다. gatekeeperd 데몬은 자체 프로세스에서 실행되며 시스템 서버와는 별개입니다.

HAL 구현

gatekeeperd 데몬은 비밀번호 인증을 위해 HAL을 사용하여 gatekeeperd 데몬의 TEE 상응 요소와 상호작용합니다. HAL 구현으로 blob에 서명(등록)하고 blob을 인증할 수 있어야 합니다. 모든 구현은 비밀번호 인증이 성공할 때마다 생성되는 인증 토큰(AuthToken)의 표준 형식을 준수해야 합니다. AuthToken의 콘텐츠 및 시맨틱에 관한 자세한 내용은 AuthToken 형식을 참조하세요.

hardware/libhardware/include/hardware/gatekeeper.h 헤더 파일의 구현으로 enrollverify 기능이 구현되어야 합니다.

  • enroll 기능은 비밀번호 blob을 가져와서 서명한 다음 서명을 핸들로 반환합니다. enroll 호출에서 반환된 blob에는 system/gatekeeper/include/gatekeeper/password_handle.h에 표시된 구조가 있어야 합니다.
  • verify 기능은 제공된 비밀번호로 생성된 서명을 비교하고 등록된 비밀번호 핸들과 일치하는지 확인해야 합니다.

등록 및 인증에 사용된 키는 변경하면 안 되며 기기가 부팅될 때마다 다시 도출할 수 있어야 합니다.

Trusty 및 기타 구현

Trusty 운영체제는 TEE 환경을 위한 신뢰할 수 있는 Google의 오픈소스 OS이며 게이트키퍼의 승인된 구현을 포함하고 있습니다. 그러나 원하는 TEE OS를 사용하여 게이트키퍼를 구현할 수 있습니다. 단, TEE가 하드웨어 지원 키 및 정지 상태에서 돌아가는 안전한 단조 시계에 액세스할 수 있어야 합니다.

Trusty는 내부 IPC 시스템을 사용하여 Keymaster, 그리고 게이트키퍼의 Trusty 구현(Trusty 게이트키퍼) 간에 직접적으로 공유된 비밀 정보를 통신합니다. 이렇게 공유된 비밀 정보는 키 저장소로 전송된 AuthToken을 서명하여 비밀번호 인증을 증명하기 위한 용도로 사용됩니다. Trusty 게이트키퍼는 사용 시마다 Keymaster에서 키를 요청하며, 지속되거나 값을 캐싱하지 않습니다. 구현은 보안을 위협하지 않는 선에서 이러한 비밀 정보를 자유롭게 공유할 수 있습니다.

비밀번호를 등록하고 인증하는 데 사용된 HMAC 키는 게이트키퍼에서만 파생 및 유지됩니다.

Android에서는 완료될 기기 전용 루틴을 추가하기만 하면 되는 게이트키퍼의 일반적인 C++ 구현을 제공합니다. TEE의 기기 전용 코드로 TEE 게이트키퍼를 구현하려면 system/gatekeeper/include/gatekeeper/gatekeeper.h의 기능과 의견을 참조하세요. TEE 게이트키퍼의 규정 준수 구현에 관한 기본 책임은 다음과 같습니다.

  • 게이트키퍼 HAL을 준수합니다.
  • AuthToken 사양(인증에서 설명됨)에 따라 반환된 AuthToken의 형식을 지정해야 합니다.
  • TEE 게이트키퍼는 요청 시 TEE PIC를 통해 키를 요청하거나 항상 값의 유효한 캐시를 유지하는 방식으로 HMAC 키를 Keymaster와 공유할 수 있어야 합니다.

사용자 보안 ID(SID)

사용자 SID는 사용자의 TEE 표현으로, Android 사용자 ID에 대한 연관성은 낮습니다. SID는 사용자가 이전 비밀번호를 제공하지 않은 상태에서 새 비밀번호를 등록할 때마다 PRNG(Pseudorandom Number Generator)를 사용하여 생성됩니다. 이를 신뢰할 수 없는 재등록이라 부르며, 일반적인 상황에서는 Android 프레임워크에 의해 허용되지 않습니다. 신뢰할 수 있는 재등록은 사용자가 유효한 이전 비밀번호를 제공하는 경우에 발생합니다. 이 경우 사용자 SID는 새 비밀번호 핸들로 이전되어 여기에 바인드된 키를 보존합니다.

비밀번호가 등록되면 사용자 SID 및 비밀번호 핸들의 비밀번호에는 HMAC가 적용됩니다.

사용자 SID는 verify 기능으로 반환된 AuthToken에 작성되고 모든 인증 바인드된 키 저장소 키에 연결됩니다. AuthToken 형식 및 키 저장소에 관한 자세한 내용은 인증을 참조하세요. 신뢰할 수 없는 enroll 기능 호출은 사용자 SID를 변경하므로 호출로 인해 그 비밀번호에 바인드된 키가 쓸모없게 됩니다. 공격자는 Android OS를 제어하는 경우 기기 비밀번호를 변경할 수 있지만 이 과정에서 루트로 보호되는 민감한 키가 제거됩니다.

요청 제한

게이트키퍼는 사용자 인증 정보에 관한 무차별 공격 시도를 안전하게 제한할 수 있어야 합니다. hardware/libhardware/include/hardware/gatekeeper.h에 표시된 것처럼 HAL은 밀리초 단위의 시간 제한을 반환할 수 있게 해줍니다. 시간 제한은 시간 제한이 경과될 때까지 게이트키퍼를 다시 호출하지 말라고 클라이언트에게 알립니다. 게이트키퍼는 시간 제한이 대기 중인 경우 요청을 처리하면 안 됩니다.

게이트키퍼는 사용자 비밀번호를 인증하기 전에 실패 카운터를 작성해야 합니다. 비밀번호 인증에 성공하면 실패 카운터가 삭제됩니다. 이렇게 하면 verify 호출 후에 삽입된 MMC(eMMC)를 사용 중지하여 제한을 방지하는 공격을 예방할 수 있습니다. enroll 기능 역시 사용자 비밀번호를 인증하며(제공된 경우) 같은 방식으로 제한되어야 합니다.

기기에서 지원하는 경우 실패 카운터를 보안 저장소에 작성하는 것이 좋습니다. 기기에서 파일 기반 암호화를 지원하지 않거나 보안 저장소가 너무 느린 경우 구현에서 RPMB(Replay Protected Memory Block)를 직접 사용할 수 있습니다.