AndroidQ 鎖屏密碼驗證流程之GateKeeper解析

本篇文章分析一下GateKeeper這個模塊,官網對GateKeeper的描述如下:

Gatekeeper

Gatekeeper 子系統會在可信執行環境 (TEE) 中執行設備解鎖圖案/密碼身份驗證。Gatekeeper 會使用由硬件支持的密鑰通過 HMAC 註冊和驗證密碼。此外,Gatekeeper 會限制連續失敗的驗證嘗試次數,並且必須根據指定的超時和指定的連續失敗嘗試次數拒絕服務請求。

當用戶驗證其密碼時,Gatekeeper 會使用 TEE 派生的共享密鑰對身份驗證認證簽名,以發送至由硬件支持的 Keystore。也就是說,Gatekeeper 認證可讓 Keystore 知道可以發佈與身份驗證綁定的密鑰(例如,應用創建的密鑰)供應用使用了。

Gatekeeper可以理解爲連接上層和底層TEE的中間層,Settings將pin/password/pattern等密碼通過Gatekeeper傳輸到TEE中去,稱爲加密(enroll)過程,Keyguard通過pin/password/pattern等密碼打開設備成爲解密(verify)過程,加解密的具體實現細節都在TEE中,我們這篇文章探究Keyguard如何將密碼送到TEE中進行解密

架構

Gatekeeper 包括以下 4 個主要組件:
gatekeeperd(Gatekeeper 守護進程)。一種 C++ Binder 服務,其中包含獨立於平臺的邏輯,並且與 GateKeeperService Java 接口相對應。

Gatekeeper HIDL服務,用於使用Gatekeeper HAL

Gatekeeper 硬件抽象層 (HAL)。 hardware/libhardware/include/hardware/gatekeeper.h中的 HAL 接口,是一個實現模塊。

Gatekeeper (TEE)。gatekeeperd 的 TEE 副本。基於 TEE 的 Gatekeeper 實現。

Gatekeeper 需要實現 Gatekeeper HAL(具體來說就是實現 hardware/libhardware/include/hardware/gatekeeper.h 中的函數)

LockSettingsService 會通過 Binder 發出一個請求,該請求會到達 Android 操作系統中的 gatekeeperd 守護進程。gatekeeperd 守護進程會發出一個請求,該請求會到達此守護進程在 TEE 中的副本 (Gatekeeper)。
引用一張官網的圖:
在這裏插入圖片描述
上面一張圖缺少了HIDL,在Android O引入Treble計劃之後,native層和HAL之間新增了HIDL,通過HwBinder來調用,實現解耦

Keyguard接收用戶輸入的密碼會通過Binder到framework層的LockSettingsService,LockSettingsService經過一系列調用會通過getGateKeeperService獲取GateKeeperService然後調用verifyChallenge方法將密碼繼續忘底層傳遞,本篇文章主要目的分析GateKeeper,keyguard和framework層相關細節不管,framework的調用棧如下:

04-30 12:01:15.647   871  1584 D dongjiao: java.lang.Exception
04-30 12:01:15.647   871  1584 D dongjiao: 	at com.android.server.locksettings.SyntheticPasswordManager.unwrapPasswordBasedSyntheticPassword(SyntheticPasswordManager.java:863)
04-30 12:01:15.647   871  1584 D dongjiao: 	at com.android.server.locksettings.LockSettingsService.spBasedDoVerifyCredential(LockSettingsService.java:2522)
04-30 12:01:15.647   871  1584 D dongjiao: 	at com.android.server.locksettings.LockSettingsService.doVerifyCredential(LockSettingsService.java:1773)
04-30 12:01:15.647   871  1584 D dongjiao: 	at com.android.server.locksettings.LockSettingsService.checkCredential(LockSettingsService.java:1746)
04-30 12:01:15.647   871  1584 D dongjiao: 	at com.android.internal.widget.ILockSettings$Stub.onTransact(ILockSettings.java:504)
04-30 12:01:15.647   871  1584 D dongjiao: 	at android.os.Binder.execTransactInternal(Binder.java:1021)
04-30 12:01:15.647   871  1584 D dongjiao: 	at android.os.Binder.execTransact(Binder.java:994)

我們從SyntheticPasswordManager的unwrapPasswordBasedSyntheticPassword方法開始,這個方法是解密過程,鎖屏密碼往下傳遞的入口

public AuthenticationResult unwrapPasswordBasedSyntheticPassword(IGateKeeperService gatekeeper,
            long handle, byte[] credential, int userId,
            ICheckCredentialProgressCallback progressCallback) throws RemoteException {
	......
		 GateKeeperResponse response = gatekeeper.verifyChallenge(fakeUid(userId), 0L,
                    pwd.passwordHandle, gkPwdToken);
	......
}

verifyChallenge方法返回有三個狀態:

    //密碼匹配失敗
    public static final int RESPONSE_ERROR = -1;
    //密碼匹配成功
    public static final int RESPONSE_OK = 0;
    //重試
    public static final int RESPONSE_RETRY = 1;

unwrapPasswordBasedSyntheticPassword中的gatekeeper是LockSettingsService的getGateKeeperService方法獲取的IGateKeeperService Binder代理端

   protected synchronized IGateKeeperService getGateKeeperService()
            throws RemoteException {
        if (mGateKeeperService != null) {
            return mGateKeeperService;
        }

        final IBinder service = ServiceManager.getService(Context.GATEKEEPER_SERVICE);
        if (service != null) {
            service.linkToDeath(new GateKeeperDiedRecipient(), 0);
            mGateKeeperService = IGateKeeperService.Stub.asInterface(service);
            return mGateKeeperService;
        }

        Slog.e(TAG, "Unable to acquire GateKeeperService");
        return null;
    }

這裏有個問題,我們發現IGateKeeperService的Binder實現端找不到,而且在Framework層也找不到在那裏註冊的service,爲何能getService,
其實IGateKeeperService這個AIDL文件的具體實現類不像傳統的Framework Binder服務,它的實現端在native層,我們前面說了GateKeeper的架構,提到GateKeeper是一種C++的Binder服務,與java層接口相對應

我們就先來來看看GateKeeper server端,目錄system/core/gatekeeperd下的gatekeeperd.cpp類

gatekeeperd.cpp

int main(int argc, char* argv[]) {
    ......
    android::sp<android::IServiceManager> sm = android::defaultServiceManager();
    android::sp<android::GateKeeperProxy> proxy = new android::GateKeeperProxy();
    android::status_t ret = sm->addService(
            android::String16("android.service.gatekeeper.IGateKeeperService"), proxy);
    if (ret != android::OK) {
        ALOGE("Couldn't register binder service!");
        return -1;
    }
    /*
     * We're the only thread in existence, so we're just going to process
     * Binder transaction as a single-threaded program.
     */
    android::IPCThreadState::self()->joinThreadPool();
    return 0;
}

gatekeeperd.cpp的main函數中,首先獲取BpSeviceManager,然後創建GateKeeperProxy類,在調用addService函數將GateKeeperProxy註冊到SeviceManager,名稱爲"android.service.gatekeeper.IGateKeeperService",前面我們在Framework層通過getService(Context.GATEKEEPER_SERVICE)獲取的gatekeeper服務其實獲取的就是這個服務,
Context中定義的服務名稱也是一樣的

 /**
     * Gatekeeper Service.
     * @hide
     */
    public static final String GATEKEEPER_SERVICE = "android.service.gatekeeper.IGateKeeperService";

繼續來看GateKeeperProxy這個類,容易想到GateKeeperProxy就是gatekeeper服務的Binder實現端,GateKeeperProxy繼承BnGateKeeperService,看名稱,BnGateKeeperService就是Binder服務端在natice層的命名規範,BnGateKeeperService定義在IGateKeeperService.h中

class BnGateKeeperService: public BnInterface<IGateKeeperService> {
  public:
      virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
              uint32_t flags = 0);
  };

BnGateKeeperService又繼承類型爲IGateKeeperService的BnInterface,
natice層的IGateKeeperService和java層的IGateKeeperService其實是對應的,所以LockSettingsService中通過getGateKeeperService獲取到的gateKeeper就是natice層GateKeeperProxy的Binder代理端,當通過這個java層代理端調用某個方法就會通過Binder調到GateKeeperProxy中來

所以前面解密過程調的verifyChallenge方法調到了gatekeeperd.cpp中的GateKeeperProxy類的同名verifyChallenge函數,但我們又發現這兩個verifyChallenge方法參數並不一致,這無所謂的,Binder調用並不需要client端和server端參數一致,調用方法的匹配是通過Binder code來決定的

到這裏,上層的鎖屏密碼就已經傳遞到了natice層,還記得前面說的gatekeeper架構嗎,native層過了之後就該通過HIDL忘HAL層發送密碼了,來看看GateKeeperProxy中的verifyChallenge具體實現

virtual int verifyChallenge(uint32_t uid, uint64_t challenge,
            const uint8_t *enrolled_password_handle, uint32_t enrolled_password_handle_length,
            const uint8_t *provided_password, uint32_t provided_password_length,
            uint8_t **auth_token, uint32_t *auth_token_length, bool *request_reenroll) {
        //省略掉一些權限相關檢查
        ......
        int ret;
        if (hw_device != nullptr) {
              //省略一些數據類型轉換
               .....
                Return<void> hwRes = hw_device->verify(hw_uid, challenge, curPwdHandle, enteredPwd,
                                        [&ret, request_reenroll, auth_token, auth_token_length]
                                             (const GatekeeperResponse &rsp) {
                    ret = static_cast<int>(rsp.code); // propagate errors
                    if (auth_token != nullptr && auth_token_length != nullptr &&
                        rsp.code >= GatekeeperStatusCode::STATUS_OK) {
                        *auth_token = new uint8_t[rsp.data.size()];
                        *auth_token_length = rsp.data.size();
                        memcpy(*auth_token, rsp.data.data(), *auth_token_length);
                        if (request_reenroll != nullptr) {
                            *request_reenroll = (rsp.code == GatekeeperStatusCode::STATUS_REENROLL);
                        }
                        ret = 0; // all success states are reported as 0
                    } else if (rsp.code == GatekeeperStatusCode::ERROR_RETRY_TIMEOUT &&
                               rsp.timeout > 0) {
                        ret = rsp.timeout;
                    }
                });
                if (!hwRes.isOk()) {
                    ALOGE("verify transaction failed\n");
                    ret = -1;
                }
            } else {
                .....
        } else {
            //如果沒有TEE硬件,則使用軟件解鎖方式
            ......
        }

       ......

        return ret;
    }

爲了代碼簡潔,上面函數省略掉了很多,我們只關心整體流程,細節的邏輯不關心,函數中涉及許多HIDL的特有語法,如果不熟悉HIDL可能會看不太懂,其實這個函數核心就做了一件事,調用hw_device->verify,將密碼通過HIDL服務繼續往HAL發送,然後通過回調獲取返回結果,verify函數最後一個參數就是一個回調函數

hw_device是個啥,來看看

public:
    GateKeeperProxy() {
        clear_state_if_needed_done = false;
        hw_device = IGatekeeper::getService();
        is_running_gsi = android::base::GetBoolProperty(android::gsi::kGsiBootedProp, false);

        if (hw_device == nullptr) {
            ALOGW("falling back to software GateKeeper");
            soft_device.reset(new SoftGateKeeperDevice());
        }
    }

hw_device是在GateKeeperProxy構造中初始化的,通過IGatekeeper::getService()賦值,在AndroidQ 打通應用層到HAL層—(HIDL服務實現)講過,IGatekeeper其實是一個HIDL接口,所以這裏獲取的是一個HIDL服務,定義在hardware/interfaces/gatekeeper/1.0中,所以hw_device->verify函數最終通過HWBinder調到了HIDL服務側,對應的具體實現類就是hardware/interfaces/gatekeeper/1.0/default目錄下的Gatekeeper.cpp,來看看具體實現:

Return<void> Gatekeeper::verify(uint32_t uid,
                                uint64_t challenge,
                                const hidl_vec<uint8_t>& enrolledPasswordHandle,
                                const hidl_vec<uint8_t>& providedPassword,
                                verify_cb cb)
{
    GatekeeperResponse rsp;
    uint8_t *auth_token = nullptr;
    uint32_t auth_token_length = 0;
    bool request_reenroll = false;

    int ret = device->verify(device, uid, challenge,
            enrolledPasswordHandle.data(), enrolledPasswordHandle.size(),
            providedPassword.data(), providedPassword.size(),
            &auth_token, &auth_token_length,
            &request_reenroll);
    if (!ret) {
        rsp.data.setToExternal(auth_token, auth_token_length, true);
        if (request_reenroll) {
            rsp.code = GatekeeperStatusCode::STATUS_REENROLL;
        } else {
            rsp.code = GatekeeperStatusCode::STATUS_OK;
        }
    } else if (ret > 0) {
        rsp.timeout = ret;
        rsp.code = GatekeeperStatusCode::ERROR_RETRY_TIMEOUT;
    } else {
        rsp.code = GatekeeperStatusCode::ERROR_GENERAL_FAILURE;
    }
    cb(rsp);
    return Void();
}

這個函數核心又通過device->verify調到HAL裏面,並將返回結果封裝爲GatekeeperResponse對象,通過前面調用hw_device->verify函數傳遞過來的回調將這個結果返回回去,這個device就是Gatekeeper HAL模塊下的具體TEE設備,它的初始化是在獲取Gatekeeper HIDL服務是進行的,如下:

Gatekeeper::Gatekeeper()
{
    int ret = hw_get_module_by_class(GATEKEEPER_HARDWARE_MODULE_ID, NULL, &module);
    device = NULL;

    if (!ret) {
        ret = gatekeeper_open(module, &device);
    }
    if (ret < 0) {
        LOG_ALWAYS_FATAL_IF(ret < 0, "Unable to open GateKeeper HAL");
    }
}

GATEKEEPER_HARDWARE_MODULE_ID是Gatekeeper HAL的模塊名稱,通過名稱獲取Gatekeeper HAL之後就可以打開HAL下的具體TEE設備了,然後在TEE中進行密碼的匹配,關於HAL相關可參考AndroidQ 打通應用層到HAL層—(HAL模塊實現)

像這種Gatekeeper HAL就可以由廠商自己實現,mtk,高通具體實現都不一樣,我們來看一個google原生的Gatekeeper HAL,目錄在/system/core/trusty/gatekeeper/下,

module.cpp

struct gatekeeper_module HAL_MODULE_INFO_SYM __attribute__((visibility("default"))) = {
      .common = {
          .tag = HARDWARE_MODULE_TAG,
          .module_api_version = GATEKEEPER_MODULE_API_VERSION_0_1,
          .hal_api_version = HARDWARE_HAL_API_VERSION,
          .id = GATEKEEPER_HARDWARE_MODULE_ID,
          .name = "Trusty GateKeeper HAL",
          .author = "The Android Open Source Project",
          .methods = &gatekeeper_module_methods,
          .dso = 0,
          .reserved = {}
      },
  };

上面是這個HAL導出的gatekeeper_module結構體,gatekeeper_module_methods函數定義的是打開此模塊下設備的函數:

static struct hw_module_methods_t gatekeeper_module_methods = {
      .open = trusty_gatekeeper_open,
  };

static int trusty_gatekeeper_open(const hw_module_t *module, const char *name,
          hw_device_t **device) {
  
      if (strcmp(name, HARDWARE_GATEKEEPER) != 0) {
          return -EINVAL;
      }
  
      TrustyGateKeeperDevice *gatekeeper = new TrustyGateKeeperDevice(module);
      if (gatekeeper == NULL) return -ENOMEM;
      *device = gatekeeper->hw_device();
  
      return 0;
  }

這個open設備的函數中創建了一個TrustyGateKeeperDevice,這個類定義在trusty_gatekeeper.cpp中

TrustyGateKeeperDevice::TrustyGateKeeperDevice(const hw_module_t *module) {
      memset(&device_, 0, sizeof(device_));
      device_.common.tag = HARDWARE_DEVICE_TAG;
      device_.common.version = 1;
      device_.common.module = const_cast<hw_module_t *>(module);
      device_.common.close = close_device;
  
      device_.enroll = enroll;
      device_.verify = verify;
      device_.delete_user = nullptr;
      device_.delete_all_users = nullptr;
  
      int rc = trusty_gatekeeper_connect();
      if (rc < 0) {
          ALOGE("Error initializing trusty session: %d", rc);
      }
      error_ = rc;  
  }

這裏面初始化了Gatekeeper HAL模塊下的device結構體,並且將verify函數賦值給了device的verify函數指針,以提供給外部使用,如果沒有廠商定義自己的Gatekeeper HAL,那麼最終鎖屏密碼的匹配就是在google這個原生HAL中執行,但現在一般Android項目的TEE都是由廠商自己實現了的,具體目錄就要看對應項目了

我們可以對整個密碼匹配的流程進行總結了:

  1. 上層Keyguard接收用戶的密碼輸入
  2. 收到密碼後通過Binder將密碼傳遞到LockSettingsService
  3. 在LockSettingsService中獲取到實現在native層的GateKeeperService,調用其verifyChallenge函數
  4. verifyChallenge中調用HIDL服務IGatekeeper的verify函數繼續向HAL中發送密碼
  5. IGatekeeper中獲取名爲GATEKEEPER_HARDWARE_MODULE_ID的HAL模塊,並打開其下的device,調用device的verify函數在TEE硬件中進最終密碼匹配
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章