Python ssl:为什么我需要将对等crt作为ca传递?

at0kjp5o  于 2023-04-06  发布在  Python
关注(0)|答案(1)|浏览(99)

我正在熟悉Python中的openssl,使用自签名证书的简单套接字服务器/客户端。有一个细节让我感到困惑。我创建了一个CA证书,我用它来自签名证书csr的使用x509为服务器和客户端生成.当使用产生的证书和私钥在服务器和客户端,我注意到,每个对等需要使用其他对等的crt作为cafile在create_缺省上下文例如,客户端在create_default_context中使用服务器的crt作为ca(),然后在load_cert_chain中输入自己的crt和key由于两个对等体的crt都使用相同的ca crt进行签名,我认为它们需要ca crt作为create_default_context的cafile(),而不是其他对等体的crt。但是如果我使用公共ca crt,我反而得到了no shared cipher错误。为什么会这样?

繁衍

  • 证书创建 *

1)CA:

openssl genrsa -aes256 -passout pass:changeme -out ca.pass.key 4096
openssl rsa -passin pass:changeme -in ca.pass.key -out ca.key
openssl req -new -x509 -days 365 -key ca.key -out ca.crt

2)客户端和服务器(其中“用户”是客户端或服务器):

openssl genrsa -aes256 -passout pass:changeme -out user.pass.key 4096
openssl rsa -passin pass:changeme -in user.pass.key -out user.key
openssl req -new -key user.key -out user.csr
openssl x509 -CAcreateserial -req -days 365 -in user.csr -CA ca.crt -CAkey ca.key -out user.crt

echo_client.py

import socket, ssl

server = ("127.0.0.1", 1234)
ssl_context = ssl.create_default_context(
    ssl.Purpose.SERVER_AUTH,
    cafile='ca.crt'
    )
ssl_context.load_cert_chain(
    certfile='client.crt',
    keyfile='client.key'
)

with socket.socket(
    socket.AF_INET,
    socket.SOCK_STREAM
    ) as session:
    with ssl_context.wrap_socket(session, server_side=False, server_hostname=server[0]) as secure_session:
        secure_session.connect(server)
        while True:
            data = bytes(input("Enter message:\n"), "ASCII")
            secure_session.sendall(data)
            echo = secure_session.recv(1024)
            print(f"Echo: {echo}")

echo_server.py

import socket, ssl, sys

def main(PORT_NUMBER):
    ssl_context = ssl.create_default_context(
        ssl.Purpose.CLIENT_AUTH,
        cafile='ca.crt'
        )
    ssl_context.load_cert_chain(
        certfile='server.crt',
        keyfile='server.key'
    )
    ssl_context.verify_mode = ssl.CERT_REQUIRED
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) as socket_fd:
        try:
            socket_fd.bind(("", PORT_NUMBER))
        except Exception as e:
            print(f"Unable to bind base socket. Reason:\n{e}")
            return(-1)
        
        socket_fd.listen(5)

        with ssl_context.wrap_socket(socket_fd, server_side=True) as secure_socket_fd:
            session_fd, client = secure_socket_fd.accept()
            with session_fd:
                print(f"Echoing {client}:")
                while True:
                    try:
                        buffer = session_fd.recv(16)
                    except ConnectionResetError:
                        try:
                            session_fd.shutdown(socket.SHUT_RDWR)
                        except:
                            pass
                        else:
                            print("Client closed the connection\nSession shutdown successful...")
                        break
                    print(f"Message received!\n{buffer}")
                    session_fd.sendall(buffer)
        
if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Must pass an address!\nExiting...")
        sys.exit(-1)
    else:
        PORT_NUMBER = int(sys.argv[1])
        sys.exit(main(PORT_NUMBER))

此配置会产生以下错误:

  • 客户端:ssl.SSLCertVerificationError:[SSL:CERTIFICATE_VERIFY_FAILED]证书验证失败:自签名证书(_ssl.c:1123)
  • 服务器:ssl.SSLError:[SSL:TLSV1_ALERT_UNKNOWN_CA] tlsv 1警报未知ca(_ssl.c:1056)
    如果我在client.py的ssl.create_default_context()中使用server.crt作为cafile,在server.py的ssl.create_default_context()中使用client.crt作为cafile,则握手成功。
    请注意,我已经根据Python的ssl指南尝试将CA连接到服务器和客户端crt。
46qrfjad

46qrfjad1#

我解决了:问题是CA的通用名与服务器的通用名相同。一旦我使用CA和服务器的不同通用名重新创建证书,它就工作了。我相信这可能是因为具有相同的通用名(因此不是CA与主题的唯一标识符)破坏了证书链的解析。

相关问题