在cryptography中添加自定义extension适配pyHanko证书注册问题
问题描述
使用cryptography库生成X509证书的代码可正常运行,但在pyHanko中创建PDF签名的SimpleSigner对象时失败。原因是将证书注册到CertificateRegistry时需要issuer_serial,但不清楚如何为证书添加该"扩展"以适配pyHanko。
证书与私钥创建代码
# Generate RSA private key private_key = rsa.generate_private_key( public_exponent=65537, key_size=2048 ) # Generate a self-signed certificate subject = issuer = x509.Name([ x509.NameAttribute(x509.NameOID.COUNTRY_NAME, u"DE"), # Country x509.NameAttribute(x509.NameOID.STATE_OR_PROVINCE_NAME, u"State"), # State x509.NameAttribute(x509.NameOID.ORGANIZATION_NAME, u"Company"), # Organization x509.NameAttribute(x509.NameOID.COMMON_NAME, user['name']), # User's common name x509.NameAttribute(x509.NameOID.EMAIL_ADDRESS, user['email']) # User's email ]) cert_builder = ( x509.CertificateBuilder() .subject_name(subject) .issuer_name(issuer) .public_key(private_key.public_key()) .serial_number(x509.random_serial_number()) .not_valid_before(datetime.utcnow()) .not_valid_after(datetime.utcnow() + timedelta(days=365)) .add_extension(x509.BasicConstraints(ca=True, path_length=None), critical=True) .sign(private_key, algorithm=hashes.SHA256(), backend=default_backend()) ) # Serialize private key to PEM format private_key_pem = private_key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.PKCS8, encryption_algorithm=serialization.NoEncryption() ) # Serialize certificate to PEM format cert_pem = cert_builder.public_bytes(encoding=serialization.Encoding.PEM) # Generate a random Fernet key for encryption fernet_key = Fernet.generate_key() # Encrypt the private key using Fernet encryption f = Fernet(fernet_key) encrypted_private_key = f.encrypt(private_key_pem) # Encode encrypted private key and fernet key to base64 encrypted_private_key_base64 = base64.b64encode(encrypted_private_key).decode('utf-8') fernet_key_base64 = base64.b64encode(fernet_key).decode('utf-8')
pyHanko中失败的代码
注册代码:
cert_store = CertificateRegistry() # Create an instance of CertificateRegistry cert_store.register(cert_pem) # Register the certificate
创建signer对象代码:
cms_signer = signers.SimpleSigner( private_key, cert, cert_registry=cert_store, )
解决方案
首先明确:issuer_serial不是X509证书的自定义扩展,而是证书固有属性的组合——发行者名称(issuer) + 证书序列号(serialNumber),pyHanko可以直接从证书对象中提取这两个值,不需要手动添加扩展。问题出在证书注册和对象传递的方式上,修正步骤如下:
- 解析证书对象:将PEM格式的证书字节解析为cryptography的
x509.Certificate对象,而不是直接传递PEM字符串给CertificateRegistry。 - 正确注册证书:使用解析后的证书对象调用
register方法,pyHanko会自动提取issuer_serial。 - 确保参数类型正确:创建
SimpleSigner时,cert参数必须是解析后的证书对象,而非PEM字节或字符串。
修改后的完整代码片段
from cryptography.x509 import load_pem_x509_certificate from pyhanko_certvalidator import CertificateRegistry from pyhanko.sign import signers # 解析证书对象(从之前生成的cert_pem) cert = load_pem_x509_certificate(cert_pem, backend=default_backend()) # 注册证书到CertificateRegistry cert_store = CertificateRegistry() cert_store.register(cert) # 传入解析后的证书对象,而非PEM字节 # 创建SimpleSigner对象 cms_signer = signers.SimpleSigner( private_key=private_key, cert=cert, cert_registry=cert_store )
额外说明
- 自签名证书的
issuer和subject相同,pyHanko依然能正确识别issuer_serial(发行者名称就是证书自身的主体名称,加上随机生成的序列号)。 - 如果仍有问题,检查证书是否包含完整的
issuer和serialNumber字段——你的证书创建代码中已经通过.issuer_name(issuer)和.serial_number(x509.random_serial_number())设置了这两个字段,所以无需额外修改证书生成逻辑。
内容的提问来源于stack exchange,提问作者KROLN
相关产品推荐
相关产品推荐

