本篇文章分析一下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都是由廠商自己實現了的,具體目錄就要看對應項目了
我們可以對整個密碼匹配的流程進行總結了:
- 上層Keyguard接收用戶的密碼輸入
- 收到密碼後通過Binder將密碼傳遞到LockSettingsService
- 在LockSettingsService中獲取到實現在native層的GateKeeperService,調用其verifyChallenge函數
- verifyChallenge中調用HIDL服務IGatekeeper的verify函數繼續向HAL中發送密碼
- IGatekeeper中獲取名爲GATEKEEPER_HARDWARE_MODULE_ID的HAL模塊,並打開其下的device,調用device的verify函數在TEE硬件中進最終密碼匹配