HTTPS执行流程解析

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HTTPS执行流程解析相关的知识,希望对你有一定的参考价值。

参考技术A

使用来自wiki的解释:

超文本传输安全协议 (英语: H yper T ext T ransfer P rotocol S ecure,缩写: HTTPS ;常称为HTTP over TLS、HTTP over SSL或HTTP Secure)是一种通过计算机网络进行安全通信的传输协议。HTTPS经由HTTP进行通信,但利用SSL/TLS来加密数据包。HTTPS开发的主要目的,是提供对网站服务器的身份认证,保护交换资料的隐私与完整性。这个协议由网景公司(Netscape)在1994年首次提出,随后扩展到互联网上。

历史上,HTTPS连接经常用于万维网上的交易支付和企业信息系统中敏感信息的传输。在2000年代末至2010年代初,HTTPS开始广泛使用,以确保各类型的网页真实,保护账户和保持用户通信,身份和网络浏览的私密性。

另外,还有一种安全超文本传输协议(S-HTTP)的HTTP安全传输实现,但是HTTPS的广泛应用而成为事实上的HTTP安全传输实现,S-HTTP并没有得到广泛支持。

ps:翻阅资料发现,S-HTTP的原理是对于每次数据的交互都进行 RSA非对称加密,对比HTTPS来说,S-HTTP加密单次事务的交互,而HTTPS则是对通信层进行加密,我想 效率和普适性 可能也是决定市场采用HTTPS而不是S-HTTP的一大因素。

传输层安全性协议 (英语: T ransport L ayer S ecurity,缩写: TLS )及其前身 安全套接层 (英语: S ecure S ockets L ayer,缩写: SSL )是一种安全协议,目的是为互联网通信提供安全及数据完整性保障。网景公司(Netscape)在1994年推出首版网页浏览器-网景导航者时,推出HTTPS协议,以SSL进行加密,这是SSL的起源。IETF将SSL进行标准化,1999年公布TLS 1.0标准文件(RFC 2246)。随后又公布TLS 1.1(RFC 4346,2006年)、TLS 1.2(RFC 5246,2008年)和TLS 1.3(RFC 8446,2018年)。在浏览器、电子邮件、即时通信、VoIP、网络传真等应用程序中,广泛使用这个协议。许多网站,如Google、Facebook、Wikipedia等也以这个协议来创建安全连线,发送资料。目前已成为互联网上保密通信的工业标准。

SSL包含记录层(Record Layer)和传输层,记录层协议确定传输层数据的封装格式。传输层安全协议使用X.509认证,之后利用非对称加密演算来对通信方做身份认证,之后交换对称密钥作为会谈密钥(Session key)。这个会谈密钥是用来将通信两方交换的资料做加密,保证两个应用间通信的保密性和可靠性,使客户与服务器应用之间的通信不被攻击者窃听。

是用于公开密钥基础建设的电子文件,用来证明公开密钥拥有者的身份。此文件包含了公钥信息、拥有者身份信息(主体)、以及数字证书认证机构(发行者)对这份文件的数字签名,以保证这个文件的整体内容正确无误。拥有者凭着此文件,可向电脑系统或其他用户表明身份,从而对方获得信任并授权访问或使用某些敏感的电脑服务。电脑系统或其他用户可以透过一定的程序核实证书上的内容,包括证书有否过期、数字签名是否有效,如果你信任签发的机构,就可以信任证书上的密钥,凭公钥加密与拥有者进行可靠的通信。

简而言之,认证机构用自己的私钥对需要认证的人(或组织机构)的公钥施加数字签名并生成证书,即证书的本质就是对公钥施加数字签名。

人们透过信任数字证书认证机构的根证书、及其使用公开密钥加密作数字签名核发的公开密钥认证,形成信任链架构,已在TLS实现并在万维网的HTTPS、在电子邮件的SMTPS和STARTTLS广泛应用。业界现行的标准是国际电信联盟电信标准化部门制定的X.509[2],并由IETF发行的RFC 5280详细述明。

X.509 是密码学里公钥证书的格式标准。X.509证书已应用在包括TLS/SSL在内的众多网络协议里,同时它也用在很多非在线应用场景里,比如电子签名服务。X.509证书里含有公钥、身份信息(比如网络主机名,组织的名称或个体名称等)和签名信息(可以是证书签发机构CA的签名,也可以是自签名)。对于一份经由可信的证书签发机构签名或者可以通过其它方式验证的证书,证书的拥有者就可以用证书及相应的私钥来创建安全的通信,对文档进行数字签名。

除了证书本身功能,X.509还附带了证书吊销列表和用于从最终对证书进行签名的证书签发机构直到最终可信点为止的证书合法性验证算法。

X.509是ITU-T标准化部门基于他们之前的ASN.1定义的一套证书标准。

Hash,一般翻译做散列、杂凑,或音译为哈希,是把任意长度的输入(又叫做预映射pre-image)通过散列算法变换成固定长度的输出,该输出就是散列值。

Hash算法也被称为散列算法,Hash算法虽然被称为算法,但实际上它更像是一种思想。Hash算法没有一个固定的公式,只要符合散列思想的算法都可以被称为是Hash算法。

特点: 无法反向破解,可以用来校验唯一性.

采用单钥密码系统的加密方法,同一个密钥可以同时用作信息的加密和解密,这种加密方法称为对称加密

常见: AES DES 3DES 特点: 效率高

一对密钥,公钥和私钥,公钥加密的数据只能通过私钥来解密,私钥加密的数据只能通过公钥解密. 保证非对称加密的安全性是极大整数的因数分解(数学实现基于互质,欧拉函数,欧拉定理,模反,具体不详细解释),wiki是这么说的:

常见: RSA 特点: 效率低,耗时长

使用http交互信息存在以下隐患:

个人来看,由于HTTP的不安全性,急需一个安全的协议做补充,而HTTPS就是在HTTP协议的基础上,添加了 传输层安全性协议(TLS/SSL) ,TLS/SSL是一个协议标准,而x.509则是这个协议标准的一个 实现 .而x.509就用到了加密相关的hash算法,对称加密算法,非对称加密算法.

1.ClientHello 首先https请求是基于http的,也就是基于tcp的,所以先得建立tcp三次握手,这个就不说了,然后tcp握手后是SSL层的握手,也就是图中的ClientHello消息,client发送本地最新的TLS版本、算法组合的一个集合和其他很多辅助的信息,并且生成一个随机数A。具体的内容可以看下图:

可以看到随机数( Random )是一个GMT UNIX时间加上一串随机字节,算法组合( Cipher Suite )有26种。

2.ServerHello Server收到这些信息后比对自己的TLS版本,选择其中低的一个作为返回,并且从算法组合的集合中选出一种合适的组合,然后同样也生成一个随机数B,一起打包到ServerHello中传回给Client。内容如图:

这里选出了一种CipherSuite算法组合。

3.Certificatie,ServerHelloDone 服务端在选出沟通策略之后将自己的证书信息告诉Client端( Certificate ),通知Client关于秘钥更新的信息( ServerkeyExchange ),接下去就看你的了,并且表示该发的都发给你了,我的Hello结束了( ServerHelloDone )。

4. Client收到2,3步的信息后先验证证书是不是合法的,包括它的颁发机构,域名匹配,有限期限等,这个具体的过程就不探究了,只要知道这些步骤就行了。

5. 证书验证通过之后,生成随机数C1,然后用证书内容中的公钥通过服务器选择的非对称加密算法加密,得出为C2。

6. 由之前的三个随机数A、B、C1通过一个伪随机函数再生成一个D, 注意!这个是最终http真正使用的加密秘钥!!!

7. 由D再次通过伪随机函数生成一个秘钥组,包含6个秘钥,假设为P1,P2,P3,P4,P5,P6。

8. ClientKeyExchange。通知Server秘钥相关的信息,发送第5步中算出的C2给Server端。

9. Client端发送ClientKeyExchange之后,计算之前所有与Server端交互消息的hash值,假设为client_hash1,用步骤7中得到的其中一个P1进行加密,结果为E。

10. Server端收到C2后用私钥结合非对称算法解密C2,得到C1。

11. 同样的Server端也根据A、B、C1由伪随机函数生成D( 最终的加密秘钥!!! ),再由D得出秘组钥(P1-P6),因为这里涉及到的算法都是一样的,所以得出的秘钥也是一样的。

12. Server端计算之前所有和Client端交互消息的hash值,假设为server_hash2,大家可能发现了,11、12跟Client端的6、7、9过程一致,只是少了9中的P1加密过程。

13. 这个时候Client端会发送ChangeCipherSpec消息和EncryptedHandshakeMessage消息,通知Server端接下去使用选定的加密策略来通信了,并且将第9步中的E传给了Server。(这里几个步骤的顺序只是为了好理解一点而这样排列,实际两条线是独立在处理信息的,所以先后顺序不能保证)

14. 这个时候Client会再次计算之前握手消息的hash值,得出结果client_hash2。

15. Server在收到EncryptedHandshakeMessage消息带过来的E之后,利用步骤11中的P1解密E,由于加密算法和P1都是相同的,所以这里还原出了client_hash1,然后与步骤12中的server_hash2比对,如果一样说明之前的几条协商秘钥的消息都被对方正确无误的理解了。

16. Server端再次对之前的消息做hash值,得出server_hash2,用P2进行加密结果为F,然后通过ChangeCipherSpec-EncryptedHandshakeMessage消息传给Client端。

17. Client收到Server的消息后根据P2解密F还原得出server_hash2,与client_hash2比对如果一致,则认为之前的交互过程都是正确无误且被对方理解的。至此,整个握手过程就结束了,之后的http数据报就会被之前确定的加密策略和加密秘钥D进行加密传输了。

总结:其实最终我们发现整个握手过程中并没有直接传输最终的加密秘钥D,而且交换了一些算法策略和生成D的一些参数,这样相对来说会更安全一点,直接传D的话这个过程就由Client端完成了,中间如果出什么差错Server会无感知无条件的信任Client传过来的D,就有可能出现问题了,所以采用只传策略和参数,并且由双方共同参与,这样安全性和正确性就会提高很多。贴一张整个过程的抓包图:

主要是为了防止 重放攻击(回放攻击) ,重放攻击是指攻击者发送一个目的主机已接收过的包,来达到欺骗系统的目的,主要用于身份认证过程,破坏认证的正确性。

浏览器客户端访问同一个https服务器,可以不必每次都进行完整的TLS Handshake,因为完整的TLS Handshake,涉及到 认证服务器的身份 (数字证书),需要做大量的非对称加密/解密运算,此外还需要做 伪随机函数PRF ,通过“ Pre-Master Key”、“Server Nonce”、“Client Nonce ”共同推导出 session key 非对称加密算法RSA/DSA非常耗费CPU资源。

为了克服这个困难,服务器维护一个以 session ID 为索引的结构体,用于临时存放session key,并在 TLS handshake 阶段分享给浏览器

当浏览器重新连接https 服务器时,TLS handshake 阶段,出示自己的session ID, 服务器获得session ID,以此为索引,可以获得和该浏览器共同拥有的session key,使用session key可以直接对用户流量做加密/解密动作。

这样避免了大量的幂、指数计算。

当然,如果服务器没有查找到session ID,双方的TLS安全参数协商按照正常流程走。

使用 charles 抓包进行分析 Session ID 的使用情况。假设有一次请求,服务端允许使用 Session ID,那么会有下面的流程:

1.客户端向服务器发起HTTPS请求

2.Charles拦截客户端的请求,伪装成客户端向服务器进行请求

3.服务器向“客户端”(实际上是Charles)返回服务器的CA证书

4.Charles拦截服务器的响应,获取服务器证书公钥,然后自己制作一张证书,将服务器证书替换后发送给客户端。(这一步,Charles拿到了服务器证书的公钥)

5.客户端接收到“服务器”(实际上是Charles)的证书后,生成一个对称密钥,用Charles的公钥加密,发送给“服务器”(Charles)

6.Charles拦截客户端的响应,用自己的私钥解密对称密钥,然后用服务器证书公钥加密,发送给服务器。(这一步,Charles拿到了对称密钥

7.服务器用自己的私钥解密对称密钥,向“客户端”(Charles)发送响应

8.Charles拦截服务器的响应,替换成自己的证书后发送给客户端

至此,连接建立,Charles拿到了 服务器证书的公钥 和 客户端与服务器协商的对称密钥,之后就可以解密或者修改加密的报文了。

(核心点:Charles生成了自己一套公钥,私钥,和自己的证书,因为自己的证书无法通过校验,所以需要客户端主动授权,客户端授权后,charles就可以完全代替客户端与服务端交互,与服务端交互用的是服务端的公钥加密,与客户端交互用的是charles自己的私钥解密)

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

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

以上是关于HTTPS执行流程解析的主要内容,如果未能解决你的问题,请参考以下文章

图文并茂源码解析MyBatis Sharding-Jdbc SQL语句执行流程详解

Spring MVC注解Controller源码流程解析--HandlerAdapter执行流程--上

步步深入:MySQL 架构总览-;查询执行流程-;SQL 解析顺序

步步深入:MySQL 架构总览-;查询执行流程-;SQL 解析顺序

步步深入:MySQL 架构总览-;查询执行流程-;SQL 解析顺序

步步深入:MySQL 架构总览-;查询执行流程-;SQL 解析顺序