如何从p7s文件提取数字签名?两种场景Python实现求助
从P7S(PKCS#7/CMS格式)文件提取数字签名值的Python实现
核心逻辑:P7S文件中的原始签名值(即加密摘要)存储在CMS结构的SignerInfo.encrypted_digest字段,与被签名载荷是否内置无关,直接解析ASN.1结构即可同时适配载荷内置、载荷外置两种场景,无需依赖密码库高层封装的签名验证接口。
依赖安装
pip install asn1crypto
完整实现代码
from asn1crypto import cms from typing import Optional, Dict, List def extract_p7s_signature(p7s_path: str, detached_content_path: Optional[str] = None) -> Dict: """ 从p7s文件提取签名相关信息,同时适配载荷内置、载荷外置两种场景 :param p7s_path: p7s签名文件路径 :param detached_content_path: 外置载荷场景下的原文件路径,内置场景无需传入 :return: 包含签名值、签名证书、载荷、签名属性的字典 """ # 读取p7s文件二进制内容 with open(p7s_path, "rb") as f: p7s_data = f.read() # 解析CMS内容结构 content_info = cms.ContentInfo.load(p7s_data) if content_info["content_type"].native != "signed_data": raise ValueError("输入文件不是合法的PKCS#7签名数据格式") signed_data = content_info["content"] result = { "signatures": [], # 存储所有签名者的原始签名值(加密摘要) "signer_certs": [], # 存储签名者证书 "signed_content": None, # 存储被签名的载荷内容 "signer_attrs": [] # 存储签名者的其他属性(含时间戳等) } # 提取被签名载荷 encap_content = signed_data["encap_content_info"] if encap_content["content"].native is not None: # 载荷内置场景:直接从p7s结构中取原内容 result["signed_content"] = encap_content["content"].native elif detached_content_path is not None: # 载荷外置场景:读取外部原文件 with open(detached_content_path, "rb") as f: result["signed_content"] = f.read() # 提取所有签名者的信息 for signer_info in signed_data["signer_infos"]: # 核心:直接取encrypted_digest字段,即为需要的加密摘要(签名本身) signature_value = signer_info["encrypted_digest"].native result["signatures"].append(signature_value) # 提取签名者证书 sid = signer_info["sid"] for cert in signed_data["certificates"]: if cert.native["tbs_certificate"]["serial_number"] == sid.native["serial_number"]: result["signer_certs"].append(cert) break # 提取签名属性(含签名时间戳等扩展信息) result["signer_attrs"].append(signer_info["signed_attrs"].native) return result
使用示例
# 场景1:载荷内置的p7s文件(p7s本身包含原文档内容) attached_result = extract_p7s_signature("attached_doc.p7s") print(f"提取到签名值(十六进制): {attached_result['signatures'][0].hex()}") print(f"内置文档长度: {len(attached_result['signed_content'])}") # 场景2:载荷外置的分离签名p7s文件(p7s不含原文档,需传入原文件路径) detached_result = extract_p7s_signature("detached_sign.p7s", detached_content_path="original.pdf") print(f"提取到签名值(十六进制): {detached_result['signatures'][0].hex()}")
关键说明
- 之前使用PyOpenSSL、Cryptography等库无法获取签名值,是因为这类库的高层API将
encrypted_digest字段封装在内部签名验证逻辑中,未暴露直接访问的属性,直接解析ASN.1结构不存在该限制 - 外置签名场景下,提取原始签名值不需要传入原文件,传入原文件仅用于后续自行做签名校验使用
- 提取到的签名值编码与签名算法匹配:RSA签名为私钥加密后的摘要原始字节,ECDSA签名为DER编码的
(r, s)整数序列
内容的提问来源于stack exchange,提问作者lcofresi
相关产品推荐
相关产品推荐

