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

如何用Python结合ECDSA与p12证书实现PDF数字签名

用ECDSA P12证书在Python中给PDF签名的解决方案

核心问题澄清

  1. P12证书容器支持ECDSA:你的P12文件只要包含ECDSA私钥、对应签名证书以及完整的证书链(可选但推荐),就具备PDF数字签名所需的全部要素——私钥用于生成ECDSA签名,证书和链用于验证身份与信任链。
  2. endesive库支持ECDSA:endesive底层依赖cryptography库,完全支持ECDSA算法签名,不需要更换库,只需确保你的P12密钥是ECDSA类型即可。

代码调整与优化

针对你提供的代码,以下是关键调整点和完整优化版本:

优化后的代码

import datetime
from cryptography.hazmat.primitives.serialization import pkcs12
from endesive.pdf import cms

def firmar(contraseña, certificado, pdf):
    # 处理签名时间(UTC时间,符合PDF规范)
    signing_date = datetime.datetime.utcnow().strftime("D:%Y%m%d%H%M%S+00'00'")
    
    # 签名配置参数
    sig_config = {
        "aligned": 0,
        "sigflags": 3,
        "sigflagsft": 132,
        "sigpage": 0,
        "sigbutton": True,
        "sigfield": "Signature1",
        "auto_sigfield": True,
        "sigandcertify": True,
        "signaturebox": (470, 640, 570, 840),  # 坐标顺序:x1(左下), y1(左下), x2(右上), y2(右上)
        "signature": "Aquí va la firma",
        "contact": "hola@ejemplo.com",
        "location": "Ubicación",
        "signingdate": signing_date,
        "reason": "Razón",
    }
    
    # 加载P12证书(新版本cryptography无需指定backend)
    private_key, cert, cert_chain = pkcs12.load_key_and_certificates(
        certificado.read(), 
        contraseña.encode("ascii")
    )
    
    # 验证密钥类型是否为ECDSA(可选,用于调试)
    from cryptography.hazmat.primitives.asymmetric import ec
    if isinstance(private_key, ec.EllipticCurvePrivateKey):
        print("检测到ECDSA私钥,符合要求")
    else:
        print("当前P12中的密钥不是ECDSA类型,请确认证书")
    
    # 读取原PDF内容
    original_pdf = pdf.read()
    
    # 生成ECDSA签名:指定sha256哈希,自动匹配ECDSA签名算法
    signed_data = cms.sign(
        original_pdf, 
        sig_config, 
        private_key, 
        cert, 
        cert_chain,  # 传入证书链,而非空列表
        "sha256"
    )
    
    # 拼接原PDF与签名数据,生成带签名的完整PDF
    signed_pdf = original_pdf + signed_data
    return signed_pdf

关键调整说明

  • 移除冗余Backend参数:新版本cryptography已默认使用最优后端,无需手动指定backends.default_backend()。
  • 修复签名坐标:PDF的坐标原点在左下角,原代码的signaturebox顺序错误,调整为左下到右上的坐标才能正确显示签名框。
  • 传递证书链:将P12中加载的cert_chain传入cms.sign,确保验证方可以完整验证证书信任链。
  • ECDSA密钥验证:添加了密钥类型检查,帮助你确认P12文件是否确实包含ECDSA私钥。
  • 简化时间处理:直接使用当前UTC时间,原代码的12小时偏移无必要。

使用示例

# 调用示例
if __name__ == "__main__":
    with open("tu_certificado.p12", "rb") as p12_file, \
         open("original.pdf", "rb") as pdf_file:
        signed_pdf = firmar("tu_contraseña", p12_file, pdf_file)
    
    with open("firmado.pdf", "wb") as output_file:
        output_file.write(signed_pdf)

常见问题排查

  1. P12密钥类型错误:如果打印显示不是ECDSA密钥,说明你的P12文件是RSA类型的,需要重新生成ECDSA类型的P12证书。
  2. 签名验证失败:确保证书链完整(P12包含中间证书),且签名哈希算法与密钥类型匹配(ECDSA推荐使用SHA256/SHA384)。
  3. 签名框不显示:检查signaturebox的坐标是否符合PDF页面尺寸(A4页面默认范围是0,0到595,842)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 16:45:33