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

如何使用Python生成包含指定配置(含alt_names)的CSR?

问题描述

需要使用Python生成符合指定配置的CSR,该配置已可通过OpenSSL实现,具体配置如下:

oid_section = OIDs
[ OIDs ]
certificateTemplateName= 1.3.6.1.4.1.311.20.2
[ req ]
default_bits        = 2048
emailAddress        = test@gmail.com
req_extensions          = v3_req
x509_extensions         = v3_ca
prompt = no
default_md = sha256
req_extensions = req_ext
distinguished_name = dn

[ dn ]
C=SA
OU=3111111117 
O=shesh
CN = tat-1

[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment

[req_ext]
certificateTemplateName = ASN1:PRINTABLESTRING:PREZATCA-Code-Signing
subjectAltName = dirName:alt_names

[alt_names]
SN=1-Device|2-234|3-mohamm
UID=30000000000000003
title=1000
registeredAddress=Zatca 12
businessCategory=Technology

已尝试使用pyOpenSSL编写代码生成CSR,但无法包含上述配置中的alt_names字段(该字段包含SN、UID等关键属性),尝试的代码如下:

from OpenSSL.SSL import FILETYPE_PEM
from OpenSSL.crypto import dump_certificate_request, dump_privatekey,dump_publickey, PKey, TYPE_DSA, X509Req
 
# create public/private key
key = PKey()
key.generate_key(TYPE_DSA,1028)

print(key.to_cryptography_key())

# Generate CSR
req = X509Req()
req.get_subject().CN = 'localhost'
req.get_subject().O = 'XYZ Widgets Inc'
req.get_subject().OU = 'IT Department'
req.get_subject().L = 'Seattle'
req.get_subject().ST = 'Washington'
req.get_subject().C = 'US'
req.get_subject().emailAddress = 'e@example.com'
req.set_pubkey(key)
req.sign(key, 'sha256')

with open("csr_testo.pem", 'wb+') as f:
    f.write(dump_certificate_request(FILETYPE_PEM, req))

with open("Private_key_testo.pem", 'wb+') as f:
    f.write(dump_privatekey(FILETYPE_PEM, key))

with open("public_key_testo.pem", 'wb+') as f:
    f.write(dump_publickey(FILETYPE_PEM, key))
解决方案

pyOpenSSL的原生API对复杂X.509扩展支持有限,尤其是dirName类型的Subject Alternative Name,需要结合其底层依赖的cryptography库实现精细控制。以下是完整的实现代码:

from OpenSSL import crypto
from cryptography import x509
from cryptography.x509.oid import NameOID, ObjectIdentifier
from cryptography.hazmat.primitives import serialization

# 自定义OID:certificateTemplateName
CERT_TEMPLATE_OID = ObjectIdentifier("1.3.6.1.4.1.311.20.2")

# 生成2048位RSA密钥(匹配原配置要求)
key = crypto.PKey()
key.generate_key(crypto.TYPE_RSA, 2048)

# 构建CSR的Distinguished Name
req = crypto.X509Req()
subject = req.get_subject()
subject.C = "SA"
subject.OU = "3111111117"
subject.O = "shesh"
subject.CN = "tat-1"
subject.emailAddress = "test@gmail.com"

# 设置公钥
req.set_pubkey(key)

# 用cryptography构建所有扩展
extensions = []

# 1. 添加basicConstraints和keyUsage(对应v3_req段)
basic_constraints = x509.BasicConstraints(ca=False, path_length=None)
extensions.append(
    x509.Extension(
        x509.oid.ExtensionOID.BASIC_CONSTRAINTS,
        critical=True,
        value=basic_constraints
    )
)

key_usage = x509.KeyUsage(
    digital_signature=True,
    non_repudiation=True,
    key_encipherment=True,
    data_encipherment=False,
    key_agreement=False,
    key_cert_sign=False,
    crl_sign=False,
    encipher_only=False,
    decipher_only=False
)
extensions.append(
    x509.Extension(
        x509.oid.ExtensionOID.KEY_USAGE,
        critical=True,
        value=key_usage
    )
)

# 2. 添加certificateTemplateName扩展
cert_template_ext = x509.UnrecognizedExtension(
    CERT_TEMPLATE_OID,
    b"PREZATCA-Code-Signing"  # 对应PRINTABLESTRING类型,直接传入字节串
)
extensions.append(cert_template_ext)

# 3. 构建alt_names对应的DirectoryName
alt_name_dir = x509.Name([
    x509.NameAttribute(NameOID.SERIAL_NUMBER, "1-Device|2-234|3-mohamm"),
    x509.NameAttribute(NameOID.USER_ID, "30000000000000003"),
    x509.NameAttribute(NameOID.TITLE, "1000"),
    x509.NameAttribute(NameOID.REGISTERED_ADDRESS, "Zatca 12"),
    x509.NameAttribute(NameOID.BUSINESS_CATEGORY, "Technology"),
])

# 添加带dirName的subjectAltName扩展
san_ext = x509.SubjectAlternativeName([
    x509.DirectoryName(alt_name_dir)
])
extensions.append(
    x509.Extension(
        x509.oid.ExtensionOID.SUBJECT_ALTERNATIVE_NAME,
        critical=False,
        value=san_ext
    )
)

# 将cryptography扩展转换为pyOpenSSL兼容格式并添加到CSR
req.add_extensions([
    crypto.X509Extension(
        ext.get_oid().dotted_string.encode(),
        ext.critical,
        ext.value.public_bytes(serialization.Encoding.DER)
    ) for ext in extensions
])

# 签名CSR
req.sign(key, "sha256")

# 保存生成的文件
with open("csr.pem", "wb") as f:
    f.write(crypto.dump_certificate_request(crypto.FILETYPE_PEM, req))

with open("private_key.pem", "wb") as f:
    f.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, key))

with open("public_key.pem", "wb") as f:
    f.write(crypto.dump_publickey(crypto.FILETYPE_PEM, key))

关键说明

  • 把原代码中的DSA密钥替换为RSA 2048位,完全匹配OpenSSL配置要求;
  • 借助cryptography实现dirName类型的Subject Alternative Name,这是pyOpenSSL原生API无法直接完成的;
  • 自定义OIDcertificateTemplateName通过UnrecognizedExtension实现,对应配置中的PRINTABLESTRING类型;
  • 所有扩展严格对齐原OpenSSL配置的参数要求,确保生成的CSR与OpenSSL命令生成的完全一致。

内容的提问来源于stack exchange,提问作者Mohammed almalki

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 20:25:17