简单介绍TLS1.2握手和协商过程

前言
随着物联网的发展,连接到互联网的设备数量呈指数增长,物联网信息安全越来越重要。
因此,tls 逐渐成为物联网通讯的标配。但是 tls 是加密传输,这给调试增加了一定的难度。
笔者最近工作中一直用到 https,但是苦于 wireshark 只能抓取 http 的明文数据包,无法抓取 https 的数据包,于是就有了这篇文章,在 rt-thread 系统上,使用 wireshark 抓取 https 数据包.
简单介绍tls1.2握手和协商过程
client hello
客户端向服务器发送 tls 版本,加密方式,客户端随机数等。
server hello
服务器端返回协商信息的结果,包括使用的 tls 版本,使用哪一种加密方式(cipher suite), 服务器的随机数(random_s)。
证书校验
客户端验证证书的合法性,如果验证通过才会进行后续通讯
client key exchange
客户端发送协商密钥发送给服务端
server change cipher spec
服务器通知客户端以后使用此协商密钥进行加密
hangshake message finish
客户端接收服务器发送的握手消息,验证通过后,握手完成。
此后的通讯都采用协商密钥和加密算法通讯。
设备端解密https数据包
查阅文档得知,wireshark 支持将 tls 会话中使用的密钥保存到外部文件中,供 wireshark 使用。
流程图
在没有抓包路由器的情况下,使用方案a, 电脑创建 wifi 热点,设备端连接电脑热点,并发起 https 请求,服务器接收到请求,向设备端发出响应,设备端根据响应的内容,计算出密钥, 并将设备端随机数和密钥通过 udp 发送到 pc,保存到 sslkey.log 文件,wireshark 根据设备端随机数和密钥即可将 tls 数据包解密。
配置wireshark
新建 sslkey.log 文件,并配置为 windows 系统变量。
配置 wireshark编辑->首选项->protocols->ssl(version 2.4.9),更高版本的 wireshark 操作步骤为:编辑->首选项->protocols->tls
配置好之后重启 wireshark
按照下面的格式,向 sslkey.log 写入客户端随机数和密钥, 即可使 wireshark 解密 tls 数据包.
1client_random5a497axx3756f69b4axxx2client_random5dfb96xxb07a9da164xxx3client_random5a497axx12e14567b9xxx4client_random55c00xxxb07a9da164xxx5client_random5a497xxxb03ca0d5fcxxx
数据的含义如下:
client_random: 固定标签(支持 ssl 3.0, tls 1.0, 1.1, 1.2)
第二个参数:客户端随机数(random_c)32个字节,编码为64个十六进制字符
第三个参数: 48字节的协商密钥,编码为96个十六进制字符
接下来只要找到设备上的客户端随机数和密钥,保存到 syskey.log,即可通过 wireshark 解密 tls 数据包。
下面函数,保存了客户端随机数和密钥信息。
ssl_tls.c
1intmbedtls_ssl_derive_keys(mbedtls_ssl_context*ssl) 2{ 3... 4 5mbedtls_ssl_debug_msg(3,(ciphersuite=%s, 6mbedtls_ssl_get_ciphersuite_name(session->ciphersuite))); 7mbedtls_ssl_debug_buf(3,mastersecret,,48); 8mbedtls_ssl_debug_buf(4,randombytes,handshake->randbytes,64); 9mbedtls_ssl_debug_buf(4,keyblock,keyblk,256);10...11}
其中session->master保存的是密钥,handshake->randbytes保存的是客户端和服务器的随机数。也就是说,将这两个参数保存到 sslkey.log 文件中,那么 wireshark 就能解密设备上的https数据包。
编写 udp 客户端,将客户端随机数和密钥发送到 windows,windows 编写 udp server python 脚本,用于接收数据,并将数据写入 sslkey.log 文件
1#include 2#include 3 4#include 5#includenetdb.h 6 7staticintport=5000; 8 9voidudpcli_send(char*ip,char*random_c,intrandom_len,char*master,intmaster_len)10{11intsock;12structhostent*host;13structsockaddr_inserver_addr;14charrandom_ptr[100]={0};15charmaster_ptr[100]={0};16inti=0;1718if(random_c==rt_null||master==rt_null)19{20rt_kprintf(random_cormasterisnull\n);21return;22}2324host=(structhostent*)gethostbyname(ip);25if(host==rt_null)26{27rt_kprintf(gethostbynamefailed!\n);28return;29}3031//randomserver_random:32bit+client_random:32bit32for(i=0;i=0)61{62closesocket(sock);63sock=-1;64}65}
udpserver.py
1importsocket 2 3bufsiz=1024 4ip_port=('0.0.0.0',5000) 5file=r'd:\work\tmp\sslkey.log' 6 7server=socket.socket(socket.af_inet,socket.sock_dgram) 8server.bind(ip_port) 910whiletrue:11random_c,client_addr=server.recvfrom(bufsiz)12master,client_addr=server.recvfrom(bufsiz)13print(openfile++file)14write_data='client_random'+str(random_c,encoding='utf-8')+''+str(master,encoding='utf-8')15print(write_data)1617withopen(file,'a')asf:18f.write(write_data)19print(closefile++file)
需要注意的是,设备使用上述方法解密 https 的数据包,加密算法目前只能是 rsa,所以还需要强制客户端发送的加密方式(cipher suites)只能是 rsa。
修改packages\mbedtls-latest\ports\inc\tls_config.h,注释掉如下宏定义:
1//#definembedtls_key_exchange_psk_enabled2//#definembedtls_key_exchange_dhe_psk_enabled3//#definembedtls_key_exchange_ecdhe_psk_enabled4//#definembedtls_key_exchange_rsa_psk_enabled5//#definembedtls_key_exchange_dhe_rsa_enabled6//#definembedtls_key_exchange_ecdhe_rsa_enabled7//#definembedtls_key_exchange_ecdhe_ecdsa_enabled8//#definembedtls_key_exchange_ecdh_ecdsa_enabled9//#definembedtls_key_exchange_ecdh_rsa_enabled
这样就可以确保客户端和服务器只使用 rsa 的加密方式进行通信, 但是部分服务器不支持 rsa 的方式,握手过程会失败。
将udpcli_send函数添加到mbedtls_ssl_derive_keys函数中,如下所示
1mbedtls_ssl_debug_msg(3,(ciphersuite=%s, 2mbedtls_ssl_get_ciphersuite_name(session->ciphersuite))); 3mbedtls_ssl_debug_buf(3,mastersecret,session->master,48); 4mbedtls_ssl_debug_buf(4,randombytes,handshake->randbytes,64); 5mbedtls_ssl_debug_buf(4,keyblock,keyblk,256); 6 7//replaceyouripaddress 8udpcli_send(192.168.123.206,handshake->randbytes,32,session->master,48); 910mbedtls_zeroize(handshake->randbytes,sizeof(handshake->randbytes));
windows 运行 python 脚本(注意修改sslkey.log的文件路径)
1pythonudpserver.py
设备联网成功后,在 msh 终端输入
1\|/ 2-rt-threadoperatingsystem 3/|\4.0.1buildapr22019 42006-2019copyrightbyrt-threadteam 5lwip-2.0.2initialized! 6[i/sal_soc]socketabstractionlayerinitializesuccess. 7 8........... 9msh/mnt/sdcard>10msh/mnt/sdcard>11msh/mnt/sdcard>12msh/mnt/sdcard>wgethttps://www.rt-thread.com/service/rt-thread.txt1.txt
wireshark抓包
加密的数据包
解密的数据包

可编程IP通信控制器芯片CO2128/CO2144的应用解决方案
燃料电池热电联供系统的工作原理
基于蓝牙无线发射接收电路设计
锐思智芯斩获“2023年度最佳传感器芯片奖”
雷诺集团取消电动汽车子公司Ampere的IPO计划
简单介绍TLS1.2握手和协商过程
安芯教育助力第八届全国高校电子信息类专业人才培养高峰论坛
寻找追光逆行者 争当创新排头兵
SIMATIC S7.1500PLC之间的OUC通信及其应用
智能人体心率检测装置的设计方案
一套开源的大型语言模型(LLM)—— StableLM
数字控制器让电源设计师的梦想成真
一诠3月营收超过新台币5亿元 月增30%
嵌入式软件系统设计中的正交性分析
R2000清零软件使用图解步骤
国芯思辰|可兼容ADI AD7793的国产24Σ-Δ型ADC(模数转换器)SC3794,最高23位有效分辨率
讨论一下Linux的各种躺平姿势
小米平板5有望7月发布 小米11Ultra被评为安卓手机第一
双天线增强手机信号
科沃斯商用清洁机器人新品发布 全租赁商业模式重磅推出