当前位置: 首页 > 工具软件 > Gatekeeper > 使用案例 >

AndroidQ 锁屏密码验证流程之GateKeeper解析

钦海荣
2023-12-01

转自: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::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;
}
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<IGateKeeperService> {
  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<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;
    }
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<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();
}
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<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;  
  }
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硬件中进最终密码匹配
 

 类似资料: