微信安全通信协议mmtls分析
本文为现代密码学课程作业。
背景
mmtls协议是TLS1.3版本的简化版或者改良版。由于TLS1.3长期处于草案状态,微信团队需要进行安全通信协议设计又无法直接使用TLS1.3协议,因此微信决定采用TLS1.3草案中的一些标准,设计了自己的mmtls协议。mmtls在微信通信层次中属于介于应用层和网络连接层之间的层次,类似于TLS在HTTP与TCP之间的位置。
微信通信过程中使用TCP进行报文传输,微信通信分为长连接和短连接两种。其中短连接使用HTTP协议加上mmtls,长连接使用私有协议加上mmtls。从内部来说,mmtls有三个子协议:Record协议、Handshake协议和Alert协议。其中Alert协议和Handshake协议作为Record协议的上层。
认证密钥协商:Handshake协议
TLS1.3中提出了2中1-RTT密钥协商方式(1-RTT ECDHE和1-RTT PSK)和4种0-RTT密钥协商方式(0-RTT ECDH、0-RTT PSK、0-RTT ECHD-ECDHE、0-RTT PSK-ECDHE),mmtls只选择了1-RTT ECDHE、1-RTT PSK和0-PSK 三种方式。其中长连接使用1-RTT ECDHE和1-RTT PSK,短连接使用0-PSK。
1-RTT ECDHE密钥协商
普通的D-H密钥协商存在被中间人攻击的可能,需要对协商数据进行身份认证,即“带认证的密钥协商”。认证有两种方式,基于MAC的对称方式和基于数字签名的非对称方式。mmtls采用数字签名的方式,使用的算法叫做ECDSA。通信双方进行密钥协商的时候,分别运行签名算法对自己的公钥进行签名,收到对方的信息后首先要验证签名,签名正确再进行密钥协商。mmtls协议中只对服务器端进行认证,不对客户端进行认证。
ECDSA的过程为,服务器收到客户端的cli_pub_key
之后,随机一对ECDH密钥svr_pub_key
、svr_pro_key
,用签名密钥sign_key
对svr_pub_key
签名得到签名值,将签名值和svr_pub_key
一同发给客户端。客户端收到之后用verify_key
进行验证,验证成功之后再继续协商密钥。其中verify_key
直接内置在微信客户端内。
1-RTT PSK密钥协商
PSK是ECDH握手中服务器下发的,包含作对称加密密钥的key以及用ticket_key对key加密后的密文ticket。PSK在安全信道中传输,只有服务器知道ticket_key。PSK协商过程中,客户端将ticket发给服务器,服务器将ticket解密后得到key,再用key计算协商的数据的HMAC进行认证。PSK使用的是对称密钥。
0-RTT PSK密钥协商
在1-RTT PSK握手之前,客户端已经得到了一个对称加密密钥,可以直接用这个密钥加密数据,和ticket一起发送给服务器,节约一个轮次。
对称加密传输:Record协议
经过握手之后,客户端和服务器端协商出了对称加密密钥pre_master_key
。我们需要加密也需要认证,在TLS1.3中只能使用AEAD类(将Encrypt和MAC集成在算法内部)的算法进行加密。mmtls选择了AES-GCM作为认证加密算法。AES-GCM中,AES为加密算法,GCM指采用Counter模式,并带有GMAC消息认证码。
对称加密需要6个加密参数,分别是:
1 | Client Write MAC Key (用于 Client 算消息认证码,以及 Server 验证消息认证码) |
pre_master_key
只有48字节,不能满足上述6个参数的需要,需要对密钥进行扩展。mmtls使用的是HKDF进行密钥扩展。在0-RTT下的pre_master_key
可能会有两个,Static Secret
和 Ephemeral Secret
。HKDF定义了两个函数进行扩展,HKDF-Extract
保证密钥的熵均匀、伪随机性足够,HKDF-Expand
对密钥的长度进行扩展。在mmtls中,pre_master_key
进过扩展,得到长度为2*enc_key_length 2*iv_length
的一段buffer,称为key_block
。剩下的4个参数就用key_block
中截取的一部分代表。
1 | client_write_key = key_block[0...enc_key_length-1] |
总结
mmtls参考了TLS1.3草案,结合微信自身背景,在密钥协商过程中使用ECDH,签名验证中使用ECDSA,认证加密中使用AES-GCM,密钥扩展中使用HKDF,摘要算法使用SHA256。