You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何将多个SIG(PKCS#7)文件合并为单个PKCS#7容器?

合并多个PKCS#7 .SIG文件为单个签名文件

要合并多个由CryptoPro、Vipnet等CSP生成的独立PKCS#7 .SIG签名文件(对应同一原始文件内容),核心难点在于**SignedCms.SignerInfos是只读集合**,无法直接将提取的签名者信息添加到新容器中。正确的做法是基于原始文件内容,重新构建一个包含所有签名者信息的SignedCms实例,具体实现步骤如下:

步骤1:准备核心数据

首先要保留所有签名对应的原始文件字节数据(也就是你代码里的msgBytes),同时读取所有.SIG文件并解码出单个签名的SignedCms对象,从中提取签名者的证书、签名值、签名属性等关键信息。

步骤2:构建合并后的签名容器

创建一个新的分离式SignedCms容器(因为你的.SIG是分离式签名,与原始文件分开存储),然后逐个将每个签名者的信息导入进去。注意不能直接复用SignerInfo对象,需要通过CmsSigner重新构造签名信息,并复用原有的签名值。

完整代码示例

// 读取原始文件内容(所有签名对应的目标文件)
byte[] msgBytes = File.ReadAllBytes("你的原始文件路径");
// 存储所有.SIG文件的路径
List<string> sigFilePaths = new List<string> { "user1.sig", "user2.sig", "user3.sig" };

// 创建新的分离式SignedCms容器
ContentInfo contentInfo = new ContentInfo(msgBytes);
SignedCms mergedSignedCms = new SignedCms(contentInfo, true);

foreach (var sigPath in sigFilePaths)
{
    // 读取并解码单个.SIG文件
    byte[] sigBytes = File.ReadAllBytes(sigPath);
    SignedCms singleSignedCms = new SignedCms(contentInfo, true);
    singleSignedCms.Decode(sigBytes);

    foreach (SignerInfo signerInfo in singleSignedCms.SignerInfos)
    {
        // 获取签名者的证书
        X509Certificate2 signerCert = signerInfo.Certificate;

        // 构造CmsSigner,复用原签名的所有属性
        CmsSigner cmsSigner = new CmsSigner(signerCert);
        cmsSigner.SignedAttributes = signerInfo.SignedAttributes;
        cmsSigner.UnsignedAttributes = signerInfo.UnsignedAttributes;

        // 复用原签名值,添加到合并后的容器中
        mergedSignedCms.AddSignature(cmsSigner, signerInfo.SignatureValue);
    }
}

// 将合并后的签名编码为字节数组,保存为新的.SIG文件
byte[] mergedSigBytes = mergedSignedCms.Encode();
File.WriteAllBytes("merged_all_signatures.sig", mergedSigBytes);

关键注意事项

  • 分离式签名验证:确保所有.SIG文件都是分离式签名(即SignedCms构造时第二个参数为true),这是多签名对应同一文件的标准模式。
  • 签名属性完整性:必须完全复用原签名的SignedAttributesUnsignedAttributes,这些属性是签名完整性的一部分,修改或丢失会导致验证失败。
  • 国产CSP兼容性:如果使用CryptoPro、Vipnet等国产CSP,要确保其.NET驱动支持SignedCms的完整操作。若遇到兼容性问题,可以尝试用CSP原生API导出签名的原始ASN.1数据,再手动导入到合并容器中。
  • 证书可用性:确保每个签名者的证书在当前运行环境中可访问(无需信任,但必须能读取到证书内容),否则会出现证书找不到的解码错误。

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

火山引擎 最新活动