0.介紹
自己開發的使用了SSL協議的軟件,通常沒必要從證書簽發機構那里來獲取證書,自簽證書成了必要的選擇。自簽證書還可以用來實現客戶端登錄認證。
1.創建CA
創建CA的私鑰 openssl genrsa -des3 -out rootCA.key 4096 創建CA的自簽證書 openssl req -x509 -new -nodes -sha256 -days 3650 -key rootCA.key -out rootCA.crt
2.簽發證書
生成證書的私鑰 openssl genrsa -out server.key 4096 生成待簽名的文件 openssl req -new -key server.key -out server.csr 使用CA進行簽名 openssl x509 -req -CA rootCA.crt -CAKey rootCA.key -CAcreateserial -days 365 -sha256 -in server.csr -out server.crt
這樣就獲取了經CA簽發的私鑰server.key和證書server.crt
3.客戶端的登錄認證
使用相同的CA來簽發服務器證書和客戶端證書,服務器就可以根據CA證書來鑒定客戶端的是否具有登錄權限。
即:凡是經過CA簽發的證書,都能登錄成功;否則失敗 。
4.Python代碼示例,演示如何驗證客戶端的證書
服務端代碼:
import socket
from socket import AF_INET, SOCK_STREAM, SO_REUSEADDR, SOL_SOCKET, SHUT_RDWR
import ssl
listen_addr = '127.0.0.1'
listen_port = 8082
server_cert = 'server.crt'
server_key = 'server.key'
ca_cert = 'rootCA.crt'
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH, cafile=ca_cert)
context.verify_mode = ssl.CERT_REQUIRED
context.load_cert_chain(certfile=server_cert, keyfile=server_key)
# context.load_verify_locations(cafile=ca_cert)
bindsocket = socket.socket()
bindsocket.bind((listen_addr, listen_port))
bindsocket.listen(5)
while True:
print("Waiting for client")
newsocket, fromaddr = bindsocket.accept()
print("Client connected: {}:{}".format(fromaddr[0], fromaddr[1]))
conn = context.wrap_socket(newsocket, server_side=True)
print("SSL established. Peer: {}".format(conn.getpeercert()))
buf = b'' # Buffer to hold received client data
try:
while True:
data = conn.recv(4096)
if data:
# Client sent us data. Append to buffer
buf += data
else:
# No more data from client. Show buffer and close connection.
print("Received:", buf)
break
finally:
print("Closing connection")
conn.shutdown(socket.SHUT_RDWR)
conn.close()
客戶端代碼
import socket
import ssl
host_addr = '127.0.0.1'
host_port = 8082
server_sni_hostname = 'example.com'
ca_cert = 'rootCA.crt'
client_cert = 'client.crt'
client_key = 'client.key'
context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH, cafile=ca_cert)
context.check_hostname = False
context.load_cert_chain(certfile=client_cert, keyfile=client_key)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
conn = context.wrap_socket(s, server_side=False, server_hostname=server_sni_hostname)
conn.connect((host_addr, host_port))
print("SSL established. Peer: {}".format(conn.getpeercert()))
print("Sending: 'Hello, world!")
conn.send(b"Hello, world!")
print("Closing connection")
conn.close()
