自签SSL证书实现客户端登录认证
- 2020 年 4 月 4 日
- 筆記
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()
参考
- 创建证书https://gist.github.com/fntlnz/cf14feb5a46b2eda428e 09
- Python的SSL代码https://www.electricmonk.nl/log/2018/06/02/ssl-tls-client-certificate-verification-with-python-v3-4-sslcontext/