目录
介绍
背景
使用代码
兴趣点
下面的代码是示例python代码段,它将连接到指定端口(例如443)的主机(例如任何www.host.com),从主机下载的证书链,并将它们存储在指定的cert_file_pathname位置
介绍我写这篇文章是为了将我的知识传授给其他开发人员,他们可能会在使用OpenSSL下载、查看和保存证书时遇到不同版本的Python(Python 2.7.x VS Python 3.7.x)。
背景在做POC时,我偶然发现了Python 2.7.x和Python 3.7.x的版本冲突。
我搜索了很多关于这个主题的公开文章和很多问答。关于此主题的信息不多。我的目的是检索证书链并将证书存储在我的本地驱动器上,这可以在其他模块中进一步使用。
使用代码下面的代码是示例python片段,它将连接到指定端口(例如443)的主机(例如任何www.host.com),从主机下载证书链并将证书存储在指定的cert_file_pathname(例如c:\testfolder\certfile)中。在代码片段中,我遍历证书列表并检索证书的CN然后打印出CN字符串。但您可以根据需要检索其他字段。
请注意,我操作cert_file_pathname并将证书的索引附加到代码中的certfile,以便我可以使用相同的前缀存储所有下载的证书。您可以根据需要修改代码以满足您的目的。
我想与大家分享这段代码,因为我意识到这方面的文章不多。我通过文章和问答以及OpenSSL和Python文档学习了这个功能
def get_certificate(host, port, cert_file_pathname):
s = socket()
context = SSL.Context(SSL.TLSv1_2_METHOD)
print('Connecting to {0} to get certificate...'.format(host))
conn = SSL.Connection(context, s)
certs = []
try:
conn.connect((host, port))
conn.do_handshake()
certs = conn.get_peer_cert_chain()
except SSL.Error as e:
print('Error: {0}'.format(str(e)))
exit(1)
try:
for index, cert in enumerate(certs):
cert_components = dict(cert.get_subject().get_components())
if(sys.version_info[0] >= 3):
cn = (cert_components.get(b'CN')).decode('utf-8')
else:
cn = cert_components.get('CN')
print('Centificate {0} - CN: {1}'.format(index, cn))
try:
temp_certname = '{0}_{1}.crt'.format(cert_file_pathname, index)
with open(temp_certname, 'w+') as output_file:
if(sys.version_info[0] >= 3):
output_file.write((crypto.dump_certificate(crypto.FILETYPE_PEM, cert).decode('utf-8')))
else:
output_file.write((crypto.dump_certificate(crypto.FILETYPE_PEM, cert)))
except IOError:
print('Exception: {0}'.format(IOError.strerror))
except SSL.Error as e:
print('Error: {0}'.format(str(e)))
exit(1)
兴趣点
我在编写代码时学习了Python 2.7.15和3.7.2之间的区别。我已经学会了可以使用的不同证书格式和安全协议。我希望这段代码能帮助像我这样的Python和SSL新手。
请注意,我使用crypto以PEM格式转储证书,但证书也可以转储到FILETYPE_ASN1中。请参阅其他参考:https://pyopenssl.org/en/stable/api/crypto.html
原文地址:https://www.codeproject.com/Tips/1278114/Python-3-How-to-download-view-and-save-Certificate