在Python中,SSL客户端的正确证书目的是什么?

5

我正在为我的python应用设置SSL客户端验证。目前,我的概念验证代码在建立安全连接方面遇到了问题。

看起来,我生成的证书可能具有没有必要权限的证书使用(在我看来更有可能),或者它们具有服务器无法理解或接受的权限(我认为这种情况较不可能)。

这应该是相对简单的,但我找不到正确的文档。

我通过OpenSSL生成了服务器和客户端证书。 我以前为其他应用程序完成过这项工作,没有任何问题。 但我对创建客户端证书的流程不太熟悉。 OpenSSL报告我正在使用的客户端证书具有扩展:

X509v3 extensions:
    X509v3 Subject Key Identifier: 
        AF:AB:9D:AA:88:96:F4:0C:F5:56:9A:2C:DB:B6:BA:D9:DD:11:69:45
    X509v3 Subject Alternative Name: 
        email:a@example.com
    X509v3 Basic Constraints: 
        CA:FALSE
    Netscape Cert Type: 
        SSL Client
    X509v3 Authority Key Identifier: 
        keyid:E1:35:7C:39:7F:39:A4:43:D2:F8:00:59:38:91:71:AF:B9:38:AD:3F

    X509v3 Key Usage: 
        Digital Signature, Key Encipherment
    X509v3 Extended Key Usage: 
        TLS Web Client Authentication

简单的服务器测试代码如下:

import ssl
import socket
import logging

_log = logging.getLogger(__name__)


def main():
    context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
    context.load_cert_chain("1B.pem", "key2.pem")
    context.verify_mode = ssl.CERT_REQUIRED
    context.load_verify_locations("my_ca.crt")

    raw_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
    try:
        # domain replaced for SO question
        raw_server_socket.bind(('neptune.example.com', 8812))
        raw_server_socket.listen(5)
        server_socket = context.wrap_socket(raw_server_socket, server_side=True)
    except Exception:
        raw_server_socket.close()
        raise

    with server_socket:
        while True:
            try:
                connection_to_client, address = server_socket.accept()
                with connection_to_client:
                    connection_to_client.write(b'Hello')
            except Exception as ex:
                print(ex)


if __name__ == "__main__":
    main()

这会产生错误:
[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unsupported certificate purpose (_ssl.c:1076)

当客户端连接时:
import socket
import ssl

context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
context.load_cert_chain("1C.pem", "key.pem")

raw_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Domain changed for SO question
conn = context.wrap_socket(raw_socket, server_side=False, server_hostname="neptune.example.com")
conn.connect(("neptune.example.com", 8812))
conn.close()


1
一个具有完全相同密钥用途、扩展密钥用途、Netscape证书类型和基本约束的客户端证书对我来说可以正常工作。请注意,此错误也可能来自证书链中的某个证书,因此最好提供涉及的所有证书或它们生成的确切方式以重现您的问题。或者您可以尝试在 https://github.com/noxxi/p5-io-socket-ssl/tree/master/certs 中使用测试证书(client-*.pem、server-*.pem、test-ca.pem)。 - Steffen Ullrich
1个回答

0

正如Steffen Ullrich所暗示的那样,问题似乎不在证书本身,而是我用来签名的CA证书。

CA证书在其可以授权的权限方面受到限制。这些权限与它们签署的证书中表示相同。因此,对于CA将证书签名为客户端SSL证书,客户端证书和CA证书都必须具备以下要求:

  • 密钥使用“数字签名”。
  • 1.3.6.1.5.5.7.3.2扩展,也称为TLS Web客户端身份验证

也就是说,openssl应该对CA证书和已签名的客户端证书都报告以下内容:

X509v3 Key Usage: 
    Digital Signature
X509v3 Extended Key Usage: 
    TLS Web Client Authentication

在我的情况下,CA并没有拓展使用1.3.6.1.5.5.7.3.2。这对于服务器证书来说没问题,但无法签署客户端证书。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接