转自:https://blog.csdn.net/qq_34211365/article/details/105833847
本篇文章分析一下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)
1
2
3
4
5
6
7
8
我们从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);
......
}
1
2
3
4
5
6
7
8
verifyChallenge方法返回有三个状态:
//密码匹配失败
public static final int RESPONSE_ERROR = -1;
//密码匹配成功
public static final int RESPONSE_OK = 0;
//重试
public static final int RESPONSE_RETRY = 1;
1
2
3
4
5
6
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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
这里有个问题,我们发现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::sp
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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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";
1
2
3
4
5
继续来看GateKeeperProxy这个类,容易想到GateKeeperProxy就是gatekeeper服务的Binder实现端,GateKeeperProxy继承BnGateKeeperService,看名称,BnGateKeeperService就是Binder服务端在natice层的命名规范,BnGateKeeperService定义在IGateKeeperService.h中
class BnGateKeeperService: public BnInterface
public:
virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
uint32_t flags = 0);
};
1
2
3
4
5
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
[&ret, request_reenroll, auth_token, auth_token_length]
(const GatekeeperResponse &rsp) {
ret = static_cast
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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
为了代码简洁,上面函数省略掉了很多,我们只关心整体流程,细节的逻辑不关心,函数中涉及许多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());
}
}
1
2
3
4
5
6
7
8
9
10
11
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
uint64_t challenge,
const hidl_vec
const hidl_vec
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();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
这个函数核心又通过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");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
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 = {}
},
};
1
2
3
4
5
6
7
8
9
10
11
12
13
上面是这个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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
这个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
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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
这里面初始化了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硬件中进最终密码匹配