使用 openssl 和 socket 实现 Client/Server 加密通信的简易测试程序。
1 证书配置
新建目录 cert
,用于存储证书文件。
1.1 创建 CA 证书
首先配置并创建 CA 证书,CA 证书配置文件 ca.conf
:
[ req ]
default_bits = 2048
default_md = sha256
distinguished_name = req_distinguished_name
x509_extensions = v3_ca
prompt = no
[ req_distinguished_name ]
C = CN
ST = HN
L = SomeCity
O = MyCompany
OU = MyDivision
CN = MyRootCA
[ v3_ca ]
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer
basicConstraints = critical, CA:true
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
生成私钥 ca.key
并创建 CA 证书 ca.crt
:
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout ca.key -out ca.crt -config ca.conf
查看证书的细节信息:
openssl x509 -in ca.crt -text -noout
部分显示如下:
1.2 创建服务器证书
同理,服务器证书配置文件 server.conf
:
[ req ]
default_bits = 2048
default_md = sha256
distinguished_name = req_distinguished_name
req_extensions = v3_req
prompt = no
[ req_distinguished_name ]
C = CN
ST = HN
L = SomeCity
O = MyCompany
OU = MyDivision
CN = 127.0.0.1
[ v3_req ]
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[ alt_names ]
DNS.1 = localhost
IP.1 = 127.0.0.1
IP.2 = 192.168.26.170
生成服务器私钥 server.key
和证书请求 server.csr
:
openssl req -new -nodes -newkey rsa:2048 -keyout server.key -out server.csr -config server.conf
使用 CA 签署服务器证书:
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 365 -extensions v3_req -extfile server.conf
查看服务器证书 server.crt
的细节信息:
openssl x509 -in server.crt -text -noout
部分显示结果如下:
2 加密通信
2.1 服务器端
# server.py
import socket
import ssl
ip_port = ('127.0.0.1', 9443)
# 生成 SSL 上下文
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
# 加载服务器所用证书和私钥
context.load_cert_chain('cert/server.crt', 'cert/server.key')
# 创建 socket 并打包成 SSL socket
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket = context.wrap_socket(server_socket, server_side=True)
# 监听端口
server_socket.bind(ip_port)
server_socket.listen(5)
while True:
# 接收客户端连接
client_socket, addr = server_socket.accept()
# 接收客户端信息
msg = client_socket.recv(1024).decode("utf-8")
print(f"receive msg from client {addr}: {msg}")
# 向客户端发送信息
msg = f"Hello, I am server.\r\n".encode("utf-8")
client_socket.send(msg)
# 关闭连接
client_socket.close()
2.2 客户端
# client.py
import socket
import ssl
ip_port = ('127.0.0.1', 9443)
# 生成SSL上下文
context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
# 加载信任根证书
context.load_verify_locations('cert/ca.crt')
# 创建 socket 并打包成 SSL socket
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 注意这里的 server_hostname 不是指服务端IP,而是指服务端证书中设置的 CN
client_socket = context.wrap_socket(client_socket, server_hostname='127.0.0.1')
# 与服务端建立连接
client_socket.connect(ip_port)
# 向服务端发送消息
msg = "Hello server, I am client.\n"
client_socket.send(msg.encode('utf-8'))
print(f"send msg to server {ip_port}: {msg}")
# 接受服务端返回的消息
msg = client_socket.recv(1024).decode("utf-8")
print(f"receive msg from server : {msg}")
client_socket.close()
2.3 运行结果
打开两个终端,一个运行 server.py
,一个运行 client.py
,运行结果如下图所示:
- 客户端向服务器发送消息 “Hello server, I am client.”
- 服务器收到来自客户端的消息并响应
- 客户端收到来自服务器的回复消息 “Hello, I am server.”