繁体   English   中英

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

[英]PyOpenSSL - how can I get SAN(Subject Alternative Names) list

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

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

我找到了一种方法,我们首先按名称检查扩展名,然后,当找到“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

PyOpenSSL建议使用cryptography因为它提供了更安全、更好的 API。 如果您可以安装加密(它是requests库的一个依赖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'])

基于@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

我做了一些深入研究,我终于找到了一些东西,所以如果其他人需要答案:

import OpenSSL

def extract_san_from_cert(cert_body):
    '''
    This function will extract the SAN (Subject Alt Names)
    from the certificate
    '''
    cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, cert_body)
    try:
        crt = cert.get_extension(6)
        data = crt.get_data()
        # ignore first 4 bytes and split in \x82\18 (,)
        san = data[4:].split('\x82\x18')
    except IndexError as err:
        # No SAN in the certificate
        san = []

    return san

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM