PyOpenSSL - 我如何获得SAN(主题备用名称)列表

时间:2018-03-26 12:41:11

标签: python pyopenssl

我正试图找到一种从给定证书中获取SAN列表的方法,但是,我在pyOpenSSL文档中找不到任何内容。

有关如何从证书中提取此数据的任何想法?

4 个答案:

答案 0 :(得分:2)

使用recommends的PyOpenSSL cryptography,因为它提供了更安全,更好的API。如果您可以安装加密技术(它是requests库的依赖项,那么已经安装了许多项目),这是获取SAN的方法:

from cryptography import x509

# classes must be subtype of:
#   https://cryptography.io/en/latest/x509/reference/#cryptography.x509.ExtensionType
san = loaded_cert.extensions.get_extension_for_class(x509.SubjectAlternativeName)
print(san)

这是从主机检索证书并打印其通用名称和SAN的完整示例。

import ssl

from cryptography import x509
from cryptography.hazmat.backends import default_backend

certificate: bytes = ssl.get_server_certificate(('example.com', 443)).encode('utf-8')
loaded_cert = x509.load_pem_x509_certificate(certificate, default_backend())

common_name = loaded_cert.subject.get_attributes_for_oid(x509.oid.NameOID.COMMON_NAME)
print(common_name)


# classes must be subtype of:
#   https://cryptography.io/en/latest/x509/reference/#cryptography.x509.ExtensionType
san = loaded_cert.extensions.get_extension_for_class(x509.SubjectAlternativeName)
san_dns_names = san.value.get_values_for_type(x509.DNSName)
print(san_dns_names)

或者,如果您要从主机下载证书,则Python的内置ssl库将为您解析SAN:

from collections import defaultdict
import socket
import ssl

hostname = 'www.python.org'
context = ssl.create_default_context()

with socket.create_connection((hostname, 443)) as sock:
    with context.wrap_socket(sock, server_hostname=hostname) as ssock:
        # https://docs.python.org/3/library/ssl.html#ssl.SSLSocket.getpeercert
        cert = ssock.getpeercert()

subject = dict(item[0] for item in cert['subject'])
print(subject['commonName'])

subjectAltName = defaultdict(set)
for type_, san in cert['subjectAltName']:
    subjectAltName[type_].add(san)
print(subjectAltName['DNS'])

答案 1 :(得分:1)

我找到了一种方法,我们首先按名称检查扩展名,然后,当" SAN"数据发现我们得到str表示并返回。

def get_certificate_san(x509cert):
    san = ''
    ext_count = x509cert.get_extension_count()
    for i in range(0, ext_count):
        ext = x509cert.get_extension(i)
        if 'subjectAltName' in str(ext.get_short_name()):
            san = ext.__str__()
    return san

答案 2 :(得分:0)

我做了一些挖掘,我终于找到了一些东西,如果其他人需要答案:

<button onclick="new thing()">Create a new thing!</button>

答案 3 :(得分:0)

基于@anatolii-chmykhalo 的回答

这将根据字符串表示返回 DNS 的替代名称。

def get_dns_altnames(req: OpenSSL.crypto.X509Req):
    """
    Get DNS altnames from a X509Req certificate

    """

    extensions = (ext for ext in req.get_extensions()
                  if ext.get_short_name() == b'subjectAltName')

    dns_names = []
    for ext in extensions:
        for alt in str(ext).split(', '):
            if alt.startswith('DNS:'):
                dns_names.append(alt[4:])

    return dns_names