하드웨어 지원 키 저장소

단일 칩 시스템(SoC)에서 신뢰할 수 있는 실행 환경이 제공되면 Android 기기에서 Android OS와 플랫폼 서비스에는 물론 타사 앱에도 강력한 보안의 하드웨어 지원 서비스를 제공할 수 있습니다. Android 전용 확장 프로그램을 만들려는 개발자는 android.security.keystore로 이동해야 합니다.

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

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

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

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

Android 7.0에서 Keymaster 2는 키 증명 및 버전 결합을 추가로 지원했습니다. 키를 안전한 하드웨어에 저장하고 키 구성을 원격으로 확인할 수 있도록 키 증명은 자세한 키 설명과 액세스 제어를 포함하는 공개키 인증서를 제공합니다.

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

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

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

Android 9 출시에 포함된 업데이트는 다음과 같습니다.

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

용어집

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

AndroidKeystore는 앱에서 키 저장소 기능에 액세스하는 데 사용하는 Android Framework API 및 구성요소입니다. 이는 표준 Java Cryptography Architecture API의 확장 프로그램으로 구현되며 앱의 자체 프로세스 공간에서 실행되는 자바 코드로 구성됩니다. AndroidKeystore는 키 저장소 데몬으로 전달하여 키 저장소 동작에 관한 앱 요청을 처리합니다.

키 저장소 데몬Binder API를 통해 모든 키 저장소 기능으로의 액세스를 제공하는 Android 시스템 데몬입니다. 이 데몬은 암호화된 실제 비밀 키 자료가 포함된 '키 blob'을 저장해야 하므로, 키 저장소는 키를 저장할 수는 있지만 사용하거나 공개할 수는 없습니다.

keymasterd는 Keymaster TA로의 액세스를 제공하는 HIDL 서버입니다. (이 이름은 표준화되지 않았으며 개념적 목적으로 사용됩니다.)

Keymaster TA(신뢰할 수 있는 애플리케이션)는 안전한 환경(ARM SoC의 TrustZone인 경우가 가장 많음)에서 실행되는 소프트웨어로서 모든 안전한 키 저장소 작업을 제공하고, 원시 키 자료에 액세스하며, 키에서 모든 액세스 제어 조건을 검증하는 작업 등을 실행합니다.

LockSettingsService는 사용자 인증(비밀번호와 지문 모두)을 담당하는 Android 시스템 구성요소입니다. 이는 키 저장소의 일부가 아니지만 키 저장소와 관련이 있습니다. 많은 키 저장소 키 작업에는 사용자 인증이 필요하기 때문입니다. LockSettingsService는 Gatekeeper TA 및 Fingerprint TA와 상호작용하여 인증 토큰을 가져와서 키 저장소 데몬에 제공합니다. 인증 토큰은 궁극적으로 Keymaster TA 애플리케이션에서 소비됩니다.

Gatekeeper TA(신뢰할 수 있는 애플리케이션)는 안전한 환경에서 실행되는 또 다른 구성요소로서 사용자 비밀번호를 인증하며, 특정 시점에 특정 사용자를 대상으로 인증이 실행되었음을 Keymaster TA에 증명하는 데 사용되는 인증 토큰을 생성합니다.

Fingerprint TA(신뢰할 수 있는 애플리케이션)는 안전한 환경에서 실행되는 다른 구성요소로서 사용자의 지문을 인증하며, 특정 시점에 특정 사용자를 대상으로 인증이 실행되었음을 Keymaster TA에 증명하는 데 사용되는 인증 토큰을 생성합니다.

아키텍처

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

Keymaster HAL은 키 저장소 서비스에서 하드웨어 지원 암호화 서비스를 제공하기 위해 사용하는 OEM 제공 라이브러리로서 동적으로 로드됩니다. 보안을 위해 HAL 구현은 사용자 공간이나 커널 공간에서 민감한 작업을 실행하지 않습니다. 민감한 작업은 일부 커널 인터페이스를 통해 연결되는 안전한 프로세서에 위임됩니다. 그 결과 생성되는 아키텍처는 다음과 같습니다.

Keymaster에 액세스

그림 1. Keymaster에 액세스

Android 기기 내에서 Keymaster HAL의 '클라이언트'는 여러 레이어(예: 앱, 프레임워크, 키 저장소 데몬)로 구성되지만 이 문서에서는 무시해도 됩니다. 즉, 설명된 Keymaster HAL API는 하위 수준이며 플랫폼 내부 구성요소에서 사용되고 앱 개발자에게 노출되지 않습니다. 더 높은 수준의 API는 Android 개발자 사이트에 설명되어 있습니다.

Keymaster HAL의 목적은 보안에 민감한 알고리즘을 구현하는 것이 아니라 안전한 세계로 요청을 마샬링 및 마샬링 취소하는 것입니다. 유선 형식은 구현으로 정의됩니다.

이전 버전과의 호환성

Keymaster 1 HAL은 Keymaster 0.2 및 0.3과 같이 이전에 출시된 HAL과 전혀 호환되지 않습니다. 키 저장소는 이전 Keymaster HAL로 출시된 Android 5.0 이전 버전을 실행하는 기기의 상호운용성을 위해 기존 하드웨어 라이브러리를 호출하여 Keymaster 1 HAL을 구현하는 어댑터를 제공합니다. 그 결과 Keymaster 1 HAL의 전체 기능을 제공할 수는 없습니다. 특히 RSA 및 ECDSA 알고리즘만 지원되며, 모든 키 승인 적용은 안전하지 않은 환경에서 어댑터에 의해 실행됩니다.

Keymaster 2는 get_supported_* 메서드를 삭제하고 finish() 메서드가 입력을 수용하도록 하여 HAL 인터페이스를 더욱 간소화합니다. 그러면 입력을 동시에 사용할 수 있는 경우 TEE로의 왕복 횟수가 줄어들고 AEAD 복호화의 구현이 간소화됩니다.

Android 8.0에서 Keymaster 3은 이전 스타일의 C 구조 HAL로부터 새 하드웨어 인터페이스 정의 언어(HIDL)의 정의에서 생성된 C++ HAL 인터페이스로 전환되었습니다. 생성된 IKeymasterDevice 클래스를 서브클래스화하고 순수한 가상 메서드를 구현함으로써 새로운 스타일의 HAL 구현이 생성됩니다. 변경사항의 일부로 많은 인수 유형이 변경되었지만 유형과 메서드는 이전 유형 및 HAL 구조 메서드와 일대일로 대응합니다.

HIDL 개요

Hardware Interface Definition Language(HIDL)는 하드웨어 인터페이스를 지정하기 위한 언어 독립적 구현 메커니즘을 제공합니다. HIDL 도구는 현재 C++ 및 자바 인터페이스의 생성을 지원합니다. 대부분의 신뢰할 수 있는 실행 환경(TEE) 구현자는 C++ 도구를 더 편리하게 사용할 수 있기 때문에 이 문서에서는 C++ 표현만 설명합니다.

HIDL 인터페이스는 다음과 같이 표현되는 일련의 메서드로 구성됩니다.

      methodName(INPUT ARGUMENTS) generates (RESULT ARGUMENTS);
    

다양한 미리 정의된 유형이 있으며 HAL은 새로운 열거형 및 구조 유형을 정의할 수 있습니다. HIDL에 관한 자세한 내용은 참조 섹션을 참조하세요.

Keymaster 3 IKeymasterDevice.hal의 메서드 예는 다음과 같습니다.

generateKey(vec<KeyParameter> keyParams)
            generates(ErrorCode error, vec<uint8_t> keyBlob,
                      KeyCharacteristics keyCharacteristics);

이는 keymaster2 HAL의 다음과 동일합니다.

keymaster_error_t (*generate_key)(
            const struct keymaster2_device* dev,
            const keymaster_key_param_set_t* params,
            keymaster_key_blob_t* key_blob,
            keymaster_key_characteristics_t* characteristics);
    

HIDL 버전에서 dev 인수는 암시적이므로 삭제됩니다. params 인수는 더 이상 key_parameter_t 객체의 배열을 참조하는 포인터를 포함하는 구조체가 아니라 KeyParameter 객체를 포함하는 vec(벡터)입니다. 반환 값은 키 blob의 uint8_t 값 벡터를 포함하는 'generates' 절에 나열됩니다.

HIDL 컴파일러에서 생성한 C++ 가상 메서드는 다음과 같습니다.

    Return<void> generateKey(const hidl_vec<KeyParameter>& keyParams,
                             generateKey_cb _hidl_cb) override;
    

여기서 generate_cb 함수 포인터는 다음과 같이 정의됩니다.

std::function<void(ErrorCode error, const hidl_vec<uint8_t>& keyBlob,
                       const KeyCharacteristics& keyCharacteristics)>
    

즉, generate_cb는 generate 절에 나열된 반환 값을 사용하는 함수입니다. HAL 구현 클래스는 이 generateKey 메서드를 재정의하고 generate_cb 함수 포인터를 호출하여 호출자에게 작업 결과를 반환합니다. 함수 포인터 호출은 동기입니다. 호출자는 generateKey를 호출하고 generateKey는 함수 포인터를 호출하여 완료될 때까지 실행합니다. 그런 다음 generateKey 구현으로 제어가 반환되고 다시 호출자에게 반환됩니다.

자세한 예는 hardware/interfaces/keymaster/3.0/default/KeymasterDevice.cpp의 기본 구현을 참조하세요. 기본 구현은 이전 스타일의 keymaster0, keymaster1 또는 keymaster2 HAL을 사용하는 기기에 이전 버전과의 호환성을 제공합니다.