TLS1.2的握手过程——从代码角度

代码角度看TLS1.2握手过程


   -- 以 ECDHE_RSA_WITH_AES_128_GCM_SHA256 密码套件为例

 

名词解释:密码套件--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为例

      ECDH  - Elliptic Curve Diffie–Hellman key exchange - 椭圆曲线迪菲-赫尔曼密钥交换
      ECDHE - (ECDH Ephemeral) 临时ECDH - 保证前向安全

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

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

    这里选择用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的内容;

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消息就是第一次加密。

- END -


 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值