1,基于TLS的Socket通信实现
1.1安装openssl
1.1.1下载地址:
http://slproweb.com/products/Win32OpenSSL.html。
1.1.2配置环境
控制面板->系统和安全->系统->高级系统设置->环境变量
1.1.3使用计算机终端切换保存路径
1.2生成CA证书
1.2.1创建CA私钥:genrsa -out ca-key.pem 2048
该命令含义如下:
genrsa——使用RSA算法产生私钥
-out——输出文件的路径
2048——指定私钥长度
1.2.2创建CA证书请求:req -new -out ca-req.csr -key ca-key.pem
该命令含义如下:
req——执行证书签发命令
-new——新证书签发请求
-out——输出的csr文件的路径
-key——指定私钥路径
1.2.3创建CA自签证书:x509 -req -in ca-req.csr -out ca-cert.pem -signkey ca-key.pem -days 365
该命令的含义如下:
x509——生成x509格式证书
-req——输入csr文件
-in——输入的csr文件的路径
-out——输出的cer证书文件的路径
-signkey——签发证书的私钥
1.2.4生成结果目录如下:
1.3生成Server证书
1.3.1创建Server私钥:genrsa -out server-key.pem 2048
1.3.2创建Server证书请求:req -new -out server-req.csr -key server-key.pem
1.3.3创建自签Server证书:x509 -req -in server-req.csr -out server-cert.pem -signkey server-key.pem -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -days 365
该命令含义如下:
-CA——指定CA证书的路径
-CAkey——指定CA证书的私钥路径
-CAserial——指定证书序列号文件的路径
-CAcreateserial——表示创建证书序列号文件(即上方提到的serial文件),创建的序列号文件默认名称为-CA,指定的证书名称后加上.srl后缀
1.3.4生成结果目录如下:
1.4python中安装openssl库
安装语句:pip install pyopenssl,import ssl无报错即安装成功。
2,实现代码
2.1服务器端实现代码
import socket
import sslclass server_ssl:def build_listen(self):# 生成SSL上下文context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)# 加载服务器所用证书和私钥context.load_cert_chain('E:\\pycharm\\ssl\\FILE\\server-cert.pem', 'E:\\pycharm\\ssl\\FILE\\server-key.pem')# 监听端口with socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) as sock:sock.bind(('127.0.0.1', 7777))sock.listen(5)# 将socket打包成SSL socketwith context.wrap_socket(sock, server_side=True) as ssock:while True:# 接收客户端连接client_socket, addr = ssock.accept()msg = client_socket.recv(1024).decode("utf-8")print(f"receive msg from client {addr}:{msg}")# 向客户端发送信息msg = f"yes , you have client_socketect with server.\r\n".encode("utf-8")client_socket.send(msg)client_socket.close()
if __name__ == "__main__":server = server_ssl()server.build_listen()在这里插入代码片
2.2客户端实现代码
import socket
import sslclass client_ssl:def send_hello(self,):# 生成SSL上下文context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)# 加载信任根证书context.load_verify_locations('E:\\pycharm\\ssl\\FILE\\ca-cert.pem')#与服务端建立socket连接with socket.create_connection(('127.0.0.1',7777)) as sock:# 将socket打包成SSL socket# 注意的是这里的server_hostname不是指服务端IP,而是指服务端证书中设置的CNwith context.wrap_socket(sock, server_hostname='test') as ssock:msg = "do i connect with server ?".encode("utf-8")ssock.send(msg)# 接收服务端返回的信息msg = ssock.recv(1024).decode("utf-8")print(f"receive msg from server : {msg}")ssock.close()if __name__ == "__main__":client = client_ssl()client.send_hello()
2.3运行结果
3,抓包分析
3.1Client Hello:
TLS记录协议首部:
内容类型(Content Type:Handshake):TLS握手协议,占一字节,0x16
TLS版本(Version):TLS1.0,占两字节,0x0301
数据长度(Length):512字节,占两字节,0x0200
TLS握手内容:
握手类型(Handshake Type):客户Hello,占一字节,0x01;
握手消息长度(Length):508字节,占三字节,0x0001fc;
TLS协议版本(Version):TLS1.2,占两字节,0x0303;
客户生成的随机数(Random):占32字节,0x9bd8d15c9094b4823d8ef1f7347f7414281b9e8c9be796293fcb9e14a62223,其中前四字节是中国标准时间,0x9bd8d15c;
会话id长度(Session ID Length):0,占一字节,0x00;
密码套件长度(Cipher suites length):130字节,占两字节,0x0082;
密码套件(65种套件)(Cipher Suites(65 suites)):占130字节,其中每一种套件占两字节,密码套件由四部分组成(基于的协议-密钥协商交换算法-加密算法和加密模式-MAC算法);
压缩算法长度(Compression Methods Length):1字节,占一字节,0x01;
压缩算法(Compression Method):无,占一字节,0x00;
扩展长度(Extensions Length):337字节,占两字节,0x0151;
扩展:服务器名称
类型:服务器名称,占两字节,0x0000;
扩展长度:9字节,占两字节,0x0009;
服务器名称指示扩展:
服务器名称列表长度(Server Name list length):7字节,占两字节,0x0007;
服务器名称类型(Server Name Type):主机名,占1字节,0x00;
服务器名称长度(Server Name length):4字节,占2字节,0x0004
服务器名称(Server Name):test,占4字节,0x74657374
扩展:椭圆曲线点格式
类型(Type):椭圆曲线点格式,占2字节,0x000b;
扩展长度:4字节,占2字节,0x0004;
椭圆曲线点格式长度:3字节,占1字节,0x03;
椭圆曲线点格式:每个占1字节;
支持的椭圆曲线类型:有13种类型,每种类型占两个字节;
支持的签名算法:有15种类型,每种算法占两个字节;
3.2服务器Hello
TLS记录协议首部
内容类型(Content Type:Handshake):TLS握手协议,占一字节,0x16
TLS版本(Version):TLS1.2,占两字节,0x0303
数据长度(Length):66字节,占两字节,0x0042
TLS握手内容:
握手类型(Handshake Type):服务器 Hello,占一字节,0x02;
握手消息长度(Length):62字节,占三字节,0x00003e;
TLS协议版本(Version):TLS1.2,占两字节,0x0303;
客户生成的随机数(Random):占32字节,0x6405d04ce1b2de387353475a46cfbd5a6d901d4efc262690ba663afed8c70b86,其中前四字节是中国标准时间,0x6405d04c;
会话id长度(Session ID Length):0,占一字节,0x00;
选择的加密套件(Cipher Suite):TLS_ECDHE_RSA_AES_256_GCM_SHA384,占两字节,0xc030
3.3服务器发送自己的证书
握手类型:证书,占两字节,0x0b;
握手消息长度:854字节,占三字节,0x000356;
证书长度:851字节,占三字节,0x000353;
证书的内容如下:
证书内容的长度:848字节,占三字节,0x000350;
序列号:15977231136593676939,占9字节,0x00ddba871156fa0a8b;
使用的签名算法:sha256withRSAEncryption;
算法标识:1.2.840.113549.1.1.11,占9字节,0x2a864886f70d01010b;
国家名称:CN,占2字节,0x4341;
州或省名称:SC,占2字节,0x5343;
地区名称:CD,占2字节,0x4344;
组织名称:no,占2字节,0x6e6f;
组织单位名称:test,占4字节,0x74657374;
邮箱地址:test,占4字节,0x74657374;
填充长度:0字节,占1字节,0x00;
有效起始时间:2019/12/19 10;58:29,占13字节,0x3139313231393130353832395a;
有效截至时间:2020/12/18 10:58:29,占13字节,0x3230313231383130353832395a;
模数(n):
公开指数(e):65537,占两字节,0x010001;
加密后的数据:占256字节;
3.4服务器发送密钥交换
服务器选择的椭圆曲线类型:secp256r1,占两字节,0x0017;
公钥长度:65字节,占一字节,0x65;
哈希算法:SHA512,占1字节,0x06;
签名算法:RSA,占1字节,0x01;
签名长度:256字节,占1字节,0x0100;
签名内容:
3.5服务器hello完毕
握手类型:服务器hello完毕,占一字节,0x0e;
3.6用户密钥交换
握手类型:用户密钥交换,占1字节,0x10;
握手内容长度:66字节,占3字节,0x000042;
客户公钥长度:65字节,占1字节,0x41;
客户公钥长度:
3.7客户端发送更改密码规范
内容类型(Content Type:Handshake):改变密码规范协议,占1字节,0x14;
数据长度(Length):1字节,占两字节,0x0101;
数据内容:0x01;
3.8客户端发送加密的握手消息
消息长度:40字节,占两字节,0x0028;
3.9服务器发送新的会话票据
握手类型:新的会话票据,占1字节,0x04;
握手数据长度:186字节,占3字节,0x0000b6;
会话票据的生存时间:300秒,占4字节,0x0000012c;
会话票据长度:176字节,占2字节,0x00b0;
会话票据内容:
3.10服务器发改变密码规则
(跟客户发送的一样这里不再作出解释)
3.11服务器发送加密的握手消息
消息长度:40字节,占两字节,0x0028;
4.参考文献
1,https://blog.csdn.net/g1531997389/article/details/80048313;
2,https://blog.csdn.net/s030602122/article/details/53538383;
3,https://blog.csdn.net/ld11690/article/details/79205566;
4,https://baike.baidu.com/item/TLS/2979545?fr=aladdin;
5,<<网络安全>>沈鑫剡等编著,清华大学出版社