-
-
代码角度看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.
也就是每做一次
hash
填
32
个字节(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
,
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
赞赏
- [原创]Arm thumb Cortex-M0 opcode 解析 3012
- IO完成端口原理 2355
- 代码角度看SSL握手过程 13490
- 给Internet Download Manager打补丁 5721
- [原创]分析X绒hrdevmon.sys,突破U盘访问控制,摄像头保护原理 9201