python 中 SSL 客户端的正确证书用途是什么?
What is the correct certificate purpose for SSL client in python?
我正在 python 应用程序中设置 SSL 客户端验证。目前,我的概念验证代码正在建立安全连接。
看来我生成的证书使用的证书没有必要的权限(更可能是 IMO)或者它们具有服务器无法理解或接受的权限( IMO).
可能性较小
这应该比较简单,但我找不到合适的文档。
我已经通过 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()
正如 Steffen Ullrich 所暗示的,问题似乎不在于证书本身,而在于我用来签署它的 CA 证书。
CA 证书在它们可以授权的权限方面受到限制。它们以与它们签署的证书相同的扩展名表示。因此,要让 CA 将证书签署为客户端 SSL 证书 both 客户端证书和 CA 证书必须具有:
- 密钥用法 "digital signature"。
1.3.6.1.5.5.7.3.2
扩展又名 TLS Web Client Authentication
也就是说,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
。服务器证书没问题,但无法签署客户端证书。
我正在 python 应用程序中设置 SSL 客户端验证。目前,我的概念验证代码正在建立安全连接。
看来我生成的证书使用的证书没有必要的权限(更可能是 IMO)或者它们具有服务器无法理解或接受的权限( IMO).
可能性较小这应该比较简单,但我找不到合适的文档。
我已经通过 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()
正如 Steffen Ullrich 所暗示的,问题似乎不在于证书本身,而在于我用来签署它的 CA 证书。
CA 证书在它们可以授权的权限方面受到限制。它们以与它们签署的证书相同的扩展名表示。因此,要让 CA 将证书签署为客户端 SSL 证书 both 客户端证书和 CA 证书必须具有:
- 密钥用法 "digital signature"。
1.3.6.1.5.5.7.3.2
扩展又名TLS Web Client Authentication
也就是说,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
。服务器证书没问题,但无法签署客户端证书。