You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过PyOpenSSL获取证书中的SAN(Subject Alternative Names)列表

Hey there! I’ve dealt with this exact problem before when working with PyOpenSSL—its official docs can be a bit sparse on this specific detail. Let me walk you through two reliable ways to extract the Subject Alternative Names (SAN) from a certificate.

方法1:直接用PyOpenSSL解析X509扩展字段

SANs are stored in an X509v3 extension with the OID 2.5.29.17. You can load the certificate, iterate through all its extensions, find this specific one, and parse its content. Here’s a working example:

from OpenSSL import crypto

def get_san_list(cert_path):
    # Load the certificate file (PEM format)
    with open(cert_path, 'rb') as cert_file:
        cert_data = cert_file.read()
    cert = crypto.load_certificate(crypto.FILETYPE_PEM, cert_data)
    
    san_entries = []
    # Loop through all extensions to find the SAN one
    for ext in cert.get_extensions():
        if ext.get_object().get_oid() == "2.5.29.17":
            # The extension's string output is formatted like "DNS:example.com, DNS:www.example.com"
            san_string = ext.__str__()
            # Split and clean up the entries
            for entry in san_string.split(', '):
                if entry.startswith('DNS:'):
                    san_entries.append(entry[4:])
                # Optional: Handle other SAN types like IP addresses
                elif entry.startswith('IP Address:'):
                    san_entries.append(entry[11:])
    return san_entries

A quick note: This method relies on parsing the string representation of the extension, which works for most standard certificates. If you’re dealing with non-standard or malformed extensions, you might want to use an ASN.1 parsing library like pyasn1 to decode the raw extension data instead of splitting strings.

方法2:结合cryptography库(更稳健)

PyOpenSSL plays nicely with the cryptography library, which has native, well-tested support for parsing SANs. This approach avoids string parsing entirely and is more reliable for edge cases. Here’s how to do it:

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

def get_san_list(cert_path):
    # Load the certificate with PyOpenSSL
    with open(cert_path, 'rb') as cert_file:
        cert_data = cert_file.read()
    openssl_cert = crypto.load_certificate(crypto.FILETYPE_PEM, cert_data)
    
    # Convert the PyOpenSSL certificate to a cryptography-compatible format
    cert_der = crypto.dump_certificate(crypto.FILETYPE_ASN1, openssl_cert)
    cryptography_cert = x509.load_der_x509_certificate(cert_der, default_backend())
    
    san_entries = []
    try:
        # Fetch the SAN extension directly
        san_extension = cryptography_cert.extensions.get_extension_for_class(x509.SubjectAlternativeName)
        # Get all DNS names (add other types like IPAddress if needed)
        san_entries = san_extension.value.get_values_for_type(x509.DNSName)
        # Uncomment below to include IP addresses too
        # san_entries.extend(san_extension.value.get_values_for_type(x509.IPAddress))
    except x509.ExtensionNotFound:
        # Handle cases where the certificate has no SAN extension
        pass
    return san_entries

Bonus Tips

  • If your certificate is in DER format instead of PEM, replace crypto.FILETYPE_PEM with crypto.FILETYPE_ASN1 when loading.
  • Make sure you have the required libraries installed: run pip install pyopenssl cryptography if you haven’t already.
  • Always handle the ExtensionNotFound exception—some older certificates don’t include SAN extensions at all.

内容的提问来源于stack exchange,提问作者Elon Salfati

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:44:55