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()

參考

相關文章