gpt4 book ai didi

python - 无法使用 OpenSSL 的 ssl.SSLContext() 在 Python 客户端中接收对等证书

转载 作者:太空宇宙 更新时间:2023-11-03 13:21:40 25 4
gpt4 key购买 nike

我是 Windows 用户。我使用 Python 3.6.5 并导入此版本的 OpenSSL OpenSSL 1.0.2k

我需要为 python TLS 客户端编写一个脚本,我可以根据支持的 TLS 版本和密码套件以及其他配置对其进行自定义。客户端应该能够使用自签名证书建立连接。因此,我相信我应该使用:ssl.SSLContext() 来创建我的上下文,而不是 ssl.create_default_context()

但是,使用以下脚本,我永远无法获得对等方的证书。请用代码提供明确的答案,否则我尝试了很多解决方案,并在没有希望的情况下查看了以前的帖子。

context = ssl.SSLContext() # ssl.create_default_context() 
#context.verify_mode = ssl.CERT_NONE
#context.check_hostname = True
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
domain="google.com"
ssl_sock = context.wrap_socket(s, server_hostname=domain)
ssl_sock.connect((domain, 443))

print("====== peer's certificate ======")
try:
cert = ssl_sock.getpeercert()
print ("issued to:", dict(itertools.chain(*cert["subject"]))["commonName"])
print ("issued by:", dict(itertools.chain(*cert["issuer"]))["commonName"])
print("issuance date:", cert["notBefore"])
print("expairy date: ", cert["notAfter"])
if (cert == None):
print("no certificate")

except Exception as e:
print("Error:",e)
ssl_sock.close()

问题是当我使用 ssl.SSLContext() 时我没有收到对等方的证书,但是当我使用 ssl.create_default_context() 时它被正确接收。但是,我需要能够接收自签名证书(即未经验证的证书),这就是我必须使用 ssl.SSLContext() 的原因。

感谢发布的解决方案。但是我需要解析证书,即使它没有经过验证(自签名)。我信任这个证书,我需要它的信息。我看了几个帖子,包括 this one .我做了这些步骤:

  1. 我获取了服务器证书的 .pem 内容。
  2. 我导航到:C:\Python36\Lib\site-packages\certifi
  3. 我打开了放在目录中的cacert.pem(第2步)
  4. 我添加了我的服务器的 cert .pem 内容,它以以下内容开头: -----BEGIN CERTIFICATE----- 并以 -----END CERTIFICATE--- 结尾--

我收到这个错误:

ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:833)

最佳答案

经过多次尝试,有些失败了,有些部分成功了,我找到了一种可行的方法(虽然没有使用自签名证书对其进行测试)。此外,我清除了之前尝试的所有内容。

有两个必要的步骤:

  1. 使用[Python 3.Docs]: (ssl.get_server_certificate(addr, ssl_version=PROTOCOL_TLS, ca_certs=None)获取服务器证书,将其作为 PEM 编码的字符串返回(例如:我们的 - pretty printed):

    '-----BEGIN CERTIFICATE-----'
    'MIIIPjCCByagAwIBAgIICG/ofYt2G48wDQYJKoZIhvcNAQELBQAwSTELMAkGA1UE'
    'BhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRl'

    ...

    'L2KuOvWZ40sTVCJdWPUMtT9VP7VHfLNTFft/IhR+bUPkr33xjOa0Idq6cL89oufn'
    '-----END CERTIFICATE-----'
  2. 使用 (!!!undocumented!!!) ssl._ssl._test_decode_cert 解码证书(存在于 Python 3/Python 2)

  3. 由于 ssl._ssl._test_decode_cert 只能从文件中读取证书,因此需要 2 个额外的步骤:

    • #1. 的证书保存在临时文件中(在#2. 之前) , 显然)

    • 完成后删除该文件

我想强调[Python 3.Docs]: SSLSocket.getpeercert(binary_form=False) ,其中包含很多信息(我上次错过了)。
此外,我通过查看 SSLSocket.getpeercert 实现("${PYTHON_SRC_DIR}/Modules/_ssl .c").

code00.py:

#!/usr/bin/env python

import itertools
import os
import socket
import ssl
import sys


def _get_tmp_cert_file_name(host, port):
return os.path.join(os.path.dirname(os.path.abspath(__file__)), "_".join(("cert", host, str(port), str(os.getpid()), ".crt")))


def _decode_cert(cert_pem, tmp_cert_file_name):
#print(tmp_cert_file_name)
with open(tmp_cert_file_name, "w") as fout:
fout.write(cert_pem)
try:
return ssl._ssl._test_decode_cert(tmp_cert_file_name)
except Exception as e:
print("Error decoding certificate:", e)
return dict()
finally:
os.unlink(tmp_cert_file_name)


def get_srv_cert_0(host, port=443):
try:
cert_pem = ssl.get_server_certificate((host, port))
except Exception as e:
print("Error getting certificate:", e)
return dict()
tmp_cert_file_name = _get_tmp_cert_file_name(host, port)
return _decode_cert(cert_pem, tmp_cert_file_name)


def get_srv_cert_1(host, port=443):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
context = ssl.SSLContext()
ssl_sock = context.wrap_socket(sock, server_hostname=host)
try:
ssl_sock.connect((host, port))
except Exception as e:
print("Error connecting:\n", e)
return dict()
try:
cert_der = ssl_sock.getpeercert(True)
except Exception as e:
print("Error getting cert:\n", e)
return dict()
tmp_cert_file_name = _get_tmp_cert_file_name(host, port)
return _decode_cert(ssl.DER_cert_to_PEM_cert(cert_der), tmp_cert_file_name)


def main(*argv):
domain = "google.com"
if argv:
print("Using custom method")
get_srv_cert_func = get_srv_cert_1
else:
print("Using regular method")
get_srv_cert_func = get_srv_cert_0

cert = get_srv_cert_func(domain)
print("====== peer's certificate ======")
try:
print("Issued To:", dict(itertools.chain(*cert["subject"]))["commonName"])
print("Issued By:", dict(itertools.chain(*cert["issuer"]))["commonName"])
print("Valid From:", cert["notBefore"])
print("Valid To:", cert["notAfter"])
if (cert == None):
print("no certificate")
except Exception as e:
print("Error getting certificate:", e)


if __name__ == "__main__":
print("Python {:s} {:03d}bit on {:s}\n".format(" ".join(elem.strip() for elem in sys.version.split("\n")),
64 if sys.maxsize > 0x100000000 else 32, sys.platform))
rc = main(*sys.argv[1:])
print("\nDone.")
sys.exit(rc)

注意事项:

  • _get_tmp_cert_file_name:生成将存储证书的临时文件名(位于与脚本相同的目录中)

  • _decode_cert:将证书保存在文件中,然后解码文件并返回生成的dict

  • get_srv_cert_0:获取证书表单服务器,然后对其进行解码

  • get_srv_cert_1:与 get_srv_cert_0 相同,但“手动”

    • 它的优势是控制 SSL 上下文创建/操作(我认为这是问题的要点)
  • 主要:

    • 使用上述两种方法之一获取服务器证书(基于传递/未传递给脚本的参数)

    • 打印证书数据(您的代码有一些小的更正)

输出:

(py35x64_test) e:\Work\Dev\StackOverflow\q050055935> "e:\Work\Dev\VEnvs\py35x64_test\Scripts\python.exe" ./code00.py
Python 3.5.4 (v3.5.4:3f56838, Aug 8 2017, 02:17:05) [MSC v.1900 64 bit (AMD64)] 064bit on win32

Using regular method
====== peer's certificate ======
Issued To: *.google.com
Issued By: Google Internet Authority G2
Valid From: Apr 10 18:58:05 2018 GMT
Valid To: Jul 3 18:33:00 2018 GMT

Done.

(py35x64_test) e:\Work\Dev\StackOverflow\q050055935> "e:\Work\Dev\VEnvs\py35x64_test\Scripts\python.exe" ./code00.py 1
Python 3.5.4 (v3.5.4:3f56838, Aug 8 2017, 02:17:05) [MSC v.1900 64 bit (AMD64)] 064bit on win32

Using custom method
====== peer's certificate ======
Issued To: *.google.com
Issued By: Google Internet Authority G2
Valid From: Apr 10 18:55:13 2018 GMT
Valid To: Jul 3 18:33:00 2018 GMT

Done.

检查 [SO]: How can I decode a SSL certificate using python? (@CristiFati's answer)仅用于解码部分。

关于python - 无法使用 OpenSSL 的 ssl.SSLContext() 在 Python 客户端中接收对等证书,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50055935/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com