使用cryptography.x509签名证书时遇缺失必需扩展错误,求排查
问题解决:证书验证提示“Certificate is missing required extension”
核心问题分析
出现该错误主要有两个原因:
- 服务器证书缺少**Extended Key Usage(扩展密钥用法)**扩展,TLS服务器证书必须明确标注用于服务器身份验证(
serverAuth) - 验证逻辑未将自签CA证书加入受信任存储,误用公网根证书库导致CA不被信任
修改后的代码
证书生成部分(添加必要扩展)
def generate_sign_sret(): from datetime import datetime, timedelta from cryptography import x509 from cryptography.x509.oid import OID_SERVER_AUTH from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives import serialization from cryptography.hazmat.backends import default_backend with open("csr.pem", "rb") as f: pem_req_data = f.read() server_csr = x509.load_pem_x509_csr(pem_req_data) with open("cert.pem", "rb") as f: ca_pem_req_data = f.read() ca_cert = x509.load_pem_x509_certificate(ca_pem_req_data) # 需提前加载CA私钥,示例: # with open("ca_private_key.pem", "rb") as f: # key = serialization.load_pem_private_key(f.read(), password=None, backend=default_backend()) # 签发服务器证书 server_cert = ( x509.CertificateBuilder() .subject_name(server_csr.subject) .issuer_name(ca_cert.subject) .public_key(server_csr.public_key()) .serial_number(x509.random_serial_number()) .not_valid_before(datetime.now() - timedelta(days=1)) .not_valid_after(datetime.now() + timedelta(days=365)) # 主机名SAN扩展 .add_extension( x509.SubjectAlternativeName([x509.DNSName("cryptography.io")]), critical=False, ) # 基础约束:明确不是CA证书 .add_extension( x509.BasicConstraints(ca=False, path_length=None), critical=True, ) # 密钥用法:适配服务器证书需求 .add_extension( x509.KeyUsage( digital_signature=True, key_encipherment=True, data_encipherment=True, key_agreement=True, key_cert_sign=False, crl_sign=False, content_commitment=True, encipher_only=False, decipher_only=False ), critical=True, ) # 新增:扩展密钥用法,指定服务器身份验证用途 .add_extension( x509.ExtendedKeyUsage([OID_SERVER_AUTH]), critical=False, ) # 使用CA私钥签发 .sign(key, hashes.SHA256(), default_backend()) ) server_cert_bytes = server_cert.public_bytes(encoding=serialization.Encoding.PEM) with open("server_cert.pem", "wb") as f: f.write(server_cert_bytes)
证书验证部分(修正信任存储)
def verifyCert(): from cryptography import x509 from cryptography.hazmat.backends import default_backend from cryptography.x509.verification import Store, PolicyBuilder, VerificationError with open("cert.pem", "rb") as f: ca_pem_req_data = f.read() ca_cert = x509.load_pem_x509_certificate(ca_pem_req_data, default_backend()) with open("server_cert.pem", "rb") as f: server_pem_req_data = f.read() server_cert = x509.load_pem_x509_certificate(server_pem_req_data, default_backend()) # 创建仅包含自签CA的受信任存储 store = Store([ca_cert]) # 构建服务器证书验证策略 trust_builder = PolicyBuilder().store(store) verifier = trust_builder.build_server_verifier(x509.DNSName("cryptography.io")) try: # 传入证书链:服务器证书在前,CA证书在后 verifier.verify(server_cert, [ca_cert]) print("Server certificate is valid.") except VerificationError as e: print("Server certificate validation failed:", e) except Exception as e: print("Unexpected error during validation:", e)
关键修改说明
- 添加Extended Key Usage扩展:这是TLS服务器证书的强制要求,明确声明证书用于服务器身份验证,直接解决“缺少必要扩展”的错误。
- 修正信任存储:将自签CA证书加入受信任列表,避免使用公网根证书库(自签CA不在公可信列表中,会导致信任链验证失败)。
- 优化密钥用法参数:关闭
key_cert_sign和crl_sign权限,符合服务器证书不能签发其他证书的特性。
内容的提问来源于stack exchange,提问作者Cheng Cui
相关产品推荐
相关产品推荐

