首页
社区
课程
招聘
代码角度看SSL握手过程
发表于: 2022-3-7 16:16 13489

代码角度看SSL握手过程

2022-3-7 16:16
13489

代码角度看SSL握手过程
-- 以 ECDHE_RSA_WITH_AES_128_GCM_SHA256 密码套件为例

QQ :181S3493S7

名词解释:密码套件--SSL握手过程联合使用了一系列加密&摘要算法,这样一组算法的集合,称为密码套件。

以下调试信息输出代码为:
https://github.com/DeDf/atls -- windows
fork自
https://github.com/mrpre/atls -- linux

测试方法:
编译运行运行atls;
下载安装openssl,openssl s_client -connect 127.0.0.1:44444;
用wireshark抓loopback包,过滤条件是tls;

(SSL服务器视角)
a_tls_handshake[1]: a_tls_get_client_hello()
a_tls_handshake[2]: a_tls_send_srv_hello()
a_tls_handshake[8]: a_tls_send_srv_cert()
a_tls_handshake[3]: a_tls_send_srv_ke() Key Exchange
a_tls_handshake[4]: a_tls_send_srv_hello_done()
a_tls_handshake[12]: a_tls_get_client_ke() Key Exchange
a_tls_handshake[11]: a_tls_get_client_ccs() Change Cipher Spec
a_tls_handshake[14]: a_tls_get_client_finished()
a_tls_handshake[6]: a_tls_send_srv_ticket()
a_tls_handshake[5]: a_tls_send_srv_ccs() Change Cipher Spec
a_tls_handshake[10]: a_tls_send_srv_finished()

a_tls_get_client_hello()
这里有个两个重要信息,和一些扩展信息
1.重要的是Client random(32 Bytes),
2.重要的是支持的加密套件list
扩展信息里给出了
1.说明了client支持的椭圆曲线list
2.支持的hash与sign算法的list;sigalg_pair_t g_sigalg_pair[A_TLS_MAX_SIG_ALG]

a_tls_send_srv_hello()
1重要的是Server random(32 Bytes),
2服务器检查client支持的密码套件组,如果服务器支持,则从中选则一个返回给client,
本文以ECDHE_RSA_WITH_AES_128_GCM_SHA256为例

a_tls_send_srv_cert()
服务器把自己的证书(链)发给client

a_tls_send_srv_ke()
服务器用ECDHE算法,选择一个server支持的椭圆曲线,本例为已命名的椭圆曲线,secp256r1,
注意client hello的扩展里可能说明了client支持的椭圆曲线list
用该椭圆曲线,生成一个65bytes的公钥;

a_tls_send_srv_hello_done()
简单(略)

a_tls_get_client_ke()
收到client的ECDH的公钥65字节,算出pms 0x20字节,
用"master secret"13字节,+ client_random 0x20字节,+ srv_random 0x20字节,共0x4d字节;
与pms 0x20字节一起,经过phash算法(内部调用HMAC算法(参数调用sha256,一种标准的hash加盐算法)),算出48字节的master_Key.

a_tls_get_client_ccs()
用""key expansion"13字节,+ srv_random 0x20字节,+ client_random 0x20字节,共0x4d字节;
与master_Key 0x30字节一起,经过phash算法(内部调用HMAC算法(参数调用sha256,一种标准的hash加盐算法)),算出0x68字节的Key_Block;
Key_Block包含读与写的cipher_key 0x10字节,IV 4字节。
a_tls_init_cipher,用Key_Block各部分(读的cipher_key 0x10字节,IV 4字节)初始化对称解密算法(AES_128_GCM);
这里初始化的是读取client消息的对称解密算法。

a_tls_get_client_finished()
第一次收到被对称加密的数据,具体解密方式(AES_128_GCM)为以前写的demo的解密算法,不再叙述;
解出来的值为,当前所有接收和发送的握手(数据类型为 HANDHSHAKE = 0x16)数据(除当前的finished消息外),经过一次sha256得到一个hash值,
"client finished" 15个字节, + 上面hash值 0x20个字节,与MASTER_KEY(48 字节)一起;
经过phash算法(内部调用HMAC算法(参数调用sha256,一种标准的hash加盐算法)),得到12字节的值,
这个值就是client发来的值,不一致的话说明被篡改;

a_tls_send_srv_ticket()
atls这里只是简单实现,不是标准;

a_tls_send_srv_ccs() Change Cipher Spec
a_tls_init_cipher,用Key_Block各部分(写的cipher_key 0x10字节,IV 4字节)初始化对称解密算法(AES_128_GCM);
这里初始化的是server发送消息的对称加密算法。

a_tls_send_srv_finished()
第一次发送被对称加密的数据;
当前所有接收和发送的握手(数据类型为 HANDHSHAKE = 0x16)数据(除当前的finished消息外),经过一次sha256得到一个hash值,
"server finished" 15个字节, + 上面hash值 0x20个字节,与MASTER_KEY(48 字节)一起;
经过phash算法(内部调用HMAC算法(参数调用sha256,一种标准的hash加盐算法)),得到12字节的值,
这个值就是发给client的值,client验证不一致的话说明被篡改;

到这里握手完毕,到client向服务器发GET了。
注意GCM加密模式,这里开始读/写都算第二次加密了,因为读/写finished消息就是第一次加密。

 
 
 
 
 
 
 
ECDH  - Elliptic Curve Diffie–Hellman key exchange - 椭圆曲线迪菲-赫尔曼密钥交换
ECDHE - (ECDH Ephemeral) 临时ECDH - 保证前向安全
ECDH  - Elliptic Curve Diffie–Hellman key exchange - 椭圆曲线迪菲-赫尔曼密钥交换
ECDHE - (ECDH Ephemeral) 临时ECDH - 保证前向安全
 
这里选择用client_hello里说明的hash与sign算法,rsa_pss_rsae_sha256 : 0x0804;
 hash算法为sha256;
  client random 32bytes + server  random 32bytes + 1 + 2 + 1 + ECDH 公钥 65bytes
  上面共0x85字节过一次hash
 
  接着是对上面hash的结果做rsa_pss_padding;
    有一个等于当前RSA密钥长度的buf(0x100字节),内容清0,密钥长度是证书决定的;
    生成一个hashlen(0x20字节)的随机数作为salt;
    buf - 1 - 0x20*2 - 1处一字节存一个"1",后面20字节存这个salt;
    0x00 * 8 8字节) + 上次hash结果(0x20字节)+ salt(0x20字节),再来一次hash
    这个hash挨着上面的salt存。
 
      然后进入mgf1算法(掩码生成函数),
      {
        用上面最后的hash值(0x20字节),加一个count(4字节 大端序),count从0开始计数;
        循环(count++)给这0x20+count4字节做hash,用这个hash,与buf[i]处异或填充buf[i],i从0到HashLen.
        也就是每做一次hash32个字节(HashLen == 0x20字节);
        填充范围是上面的buf从头到(buf+0x100-HashLen-1)处;
        最后不到20字节的,按实际剩余字节数填充。
        buf最后一个字节置0xbc,首字节out[0] &= 0xFF >> 1;
      }
      mgf1算法结束,拼出buf(0x100字节:RSA密钥长度);
 
  然后 RSA_private_encrypt(0x100, buf(0x100字节), out, rsa, RSA_NO_PADDING) 生成的out也是0x100字节;
  0x100个字节就是RSA sign的内容;
这里选择用client_hello里说明的hash与sign算法,rsa_pss_rsae_sha256 : 0x0804;
 hash算法为sha256;
  client random 32bytes + server  random 32bytes + 1 + 2 + 1 + ECDH 公钥 65bytes

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2022-3-30 11:06 被囧囧编辑 ,原因:
收藏
免费 3
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//