转自: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硬件中进最终密码匹配

AndroidQ 锁屏密码验证流程之GateKeeper解析相关推荐

  1. Android11.0(R) 预留清空锁屏密码接口

    前言 出厂的设备有些客户喜欢设置锁屏密码,无奈记性不好,忘记密码后就只能恢复出厂或者重新刷机了,啊这客户肯定不接受的. 为了防止客户逼逼赖赖,我们就未雨绸缪,给它加个清除接口. 先说结论,系统锁屏密码 ...

  2. AndroidQ 获取、设置锁屏密码

    AndroidQ 获取.设置锁屏密码 本文中贴出的源码均为AndroidQ(9.0)源码,如果想要使用需要引入Framework的jar包 LockPatternUtils 说到密码相关的一定要提到L ...

  3. android锁屏密码文件夹,深入理解Android M 锁屏密码存储方式

    Android M 之前锁屏密码的存储 在 Android M 之前,锁屏密码的存储格式很简单,其使用了 64 位随机数作为 salt 值,此 salt 值被存储在 sqlite 数据库 /data/ ...

  4. java修改手机锁屏密码,深入理解Android M 锁屏密码存储方式

    Android M 之前锁屏密码的存储 在 Android M 之前,锁屏密码的存储格式很简单,其使用了 64 位随机数作为 salt 值,此 salt 值被存储在 SQLite 数据库 /data/ ...

  5. 如何设置电脑自动锁屏_这个手机锁屏密码竟可以根据时间而变化!密码每分钟都会发生改变...

    如今,手机已经成为了我们生活中不可或缺的一部分.手机里面承载了我们太多的个人信息.生活隐私,财产安全等等.为了防止别人偷窥我们的手机,我们都会将手机设置锁屏密码. 相信大家锁屏设置的都是图形或者数字密 ...

  6. 怎么重置blockinput的锁_OPPOA9锁屏密码忘了怎么办? OPPO忘记锁屏密码的解决办法...

    看点:iPhone X原装屏与国产屏有哪些区别? 看点:换7P.8P屏幕:C11和DTP和DKH的区别 狮淘:不锈钢拆机片5个只需9.9元!包邮!每天10名 OPPOA9锁屏密码忘了怎么办?OPPO ...

  7. iphone已停用怎么解锁_iPhone 已停用怎么办?使用锁屏密码需要注意

    在我们购买一款新手机之后,一般都会设置锁屏密码来保护个人隐私与信息安全.那么,你真的了解 iPhone 的锁屏密码吗?如何设置锁屏密码更安全?如果不小心密码输错多次设备被停用怎么办?今天就来为大家简单 ...

  8. 锁屏界面提示某些设置已隐藏_OPPO忘记锁屏密码怎么办?教你一招轻松解开!...

    忘记锁屏密码怎么办 打不开手机好着急 现在不用担心, 教你一招解锁 再也不用怕忘记密码啦 一起来看看吧~ 解锁方式1 1.如果之前有通过[设置]-[指纹.面部与密码]-[锁屏密码]-[绑定安全邮箱]设 ...

  9. 如何刷机:iphone8锁屏密码错误多次,手机停用,连接iTunes,磁盘已满,双重认证弊端!

    前两天,我正玩着的手机突然提示IOS系统升级,随手点了个"稍后",再等会打开手机时却要输入密码,问题来了:输了多次锁屏密码一直不对,但我的密码确实没改过,怀疑是系统漏洞所致,最后手 ...

最新文章

  1. boost::mp11::mp_any_of_q相关用法的测试程序
  2. python用format保留三位小数_关于Python 保留小数使用format、%、round()、Decimal函数及format和%只能保留到六位问题...
  3. 什么是document对象?如何获取文档对象上的元素?_dom对象
  4. java运动员最佳配对_运动员最佳配对问题 - osc_y1pyjby5的个人空间 - OSCHINA - 中文开源技术交流社区...
  5. 4、Kafka常见问题
  6. (30)Gulp 文件操作
  7. Adobe正式在中国市场推出Creative Cloud创意应用软件
  8. 字符串反转的进一步应用----单词反转
  9. matlab j计算丰水期的值,科学计算与MATLAB语言超星2020期末考试查题公众号答案
  10. 进度猫带你来了解,一个优秀的管理者都有哪些准则
  11. Excel如何统计单元格中姓名个数
  12. 各双拼输入方案之间有明显的优劣之分吗?
  13. 在线android机型测试,免费兼容测试/MonkeyTest/100款安卓机型真机测试
  14. java 定时凌晨_java Timer 定时每天凌晨1点执行任务
  15. 摄像头poe供电原理_监控摄像头poe供电维修方法
  16. 【Python】np.where()替换缺失值
  17. 线性代数 行列式(二)
  18. 基于scapy实现随机源IP的DNS发包工具
  19. 几款主流快速开发平台比较
  20. Android 停车地图及停车导航,停车场蓝牙定位导航方案

热门文章

  1. Java学习 之 画图板 立方体
  2. 个人整理shell脚本编程笔记
  3. python中test的用法_Python基础介绍 | 使用pytest进行测试
  4. java方向考什么证_java认证证书两个工作方向
  5. STC89C52控制74HC595,74HC138双色16x16点阵屏循环显示汉字
  6. 【数字逻辑】学习笔记 第四章 Part2 常用组合逻辑电路与竞争、险象
  7. NSDTF-DEM格式高程数据转通用的tiff格式高程数据
  8. 飞桨框架v2.3 API最新升级!对科学计算、概率分布和稀疏Tensor等提供更全面支持!...
  9. 关于HTML中常用选择器
  10. google浏览器打包扩展程序