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

如何用C#生成与指定OpenSSL命令等效的PKCS #7签名

问题解决:用BouncyCastle生成匹配OpenSSL SMIME签名的CMS结构

核心要点匹配OpenSSL参数

你的目标是生成和openssl smime -sign -binary -outform DER -noattr -nosmimecap完全一致的CMS签名,需注意这些参数对应的CMS结构特征:

  • -noattr:不包含签名属性(SignedAttributes),因此SignerInfo的signedAttributes必须设为null
  • 签名算法为SHA256withRSA,对应OID 1.2.840.113549.1.1.11,而非单纯的RSA加密OID
  • 输出为DER编码的CMS SignedData结构

修正后的代码实现

以下是调整后的C#代码,完全匹配你的OpenSSL命令输出:

using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.Pkcs;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.X509;
using System.IO;

// 已知参数
byte[] rawSignedDigest = /* 从Azure Key Vault获取的RSA签名后的SHA256摘要 */;
string certPath = "./path/to/mycert.crt";

// 1. 加载证书
X509Certificate cert = new X509CertificateParser().ReadCertificate(File.ReadAllBytes(certPath));

// 2. 定义算法标识符
DerObjectIdentifier sha256Oid = new DerObjectIdentifier("2.16.840.1.101.3.4.2.1"); // SHA256
AlgorithmIdentifier digestAlg = new AlgorithmIdentifier(sha256Oid, DerNull.Instance);

DerObjectIdentifier sha256WithRsaOid = new DerObjectIdentifier("1.2.840.113549.1.1.11"); // SHA256withRSA
AlgorithmIdentifier signatureAlg = new AlgorithmIdentifier(sha256WithRsaOid, DerNull.Instance);

// 3. 构建证书集合(使用DerSet,匹配OpenSSL的编码方式)
Asn1EncodableVector certVector = new Asn1EncodableVector();
certVector.Add(Asn1Object.FromByteArray(cert.GetEncoded()));
DerSet certs = new DerSet(certVector);

// 4. 构建SignerInfo
SignerInfo signerInfo = new SignerInfo(
    DerInteger.One, // 版本号
    new IssuerAndSerialNumber(cert.IssuerDN, cert.SerialNumber),
    digestAlg,
    null, // 对应-noattr,不设置签名属性
    signatureAlg,
    new DerOctetString(rawSignedDigest), // 传入已签名的摘要
    null // 无未签名属性
);

// 5. 构建SignedData和最终ContentInfo
ContentInfo dataContentInfo = new ContentInfo(PkcsObjectIdentifiers.Data, null);
SignedData signedData = new SignedData(
    DerInteger.One, // 版本号
    new DerSet(digestAlg), // 摘要算法集合
    dataContentInfo,
    certs,
    null, // 无CRL
    new DerSet(signerInfo)
);

ContentInfo finalContentInfo = new ContentInfo(PkcsObjectIdentifiers.SignedData, signedData);

// 生成最终的DER编码签名结果
byte[] result = finalContentInfo.GetEncoded(Asn1Encodable.Der);

关键修正点说明

  1. 签名算法OID修正:原代码使用PkcsObjectIdentifiers.RsaEncryption(仅RSA加密),但OpenSSL的smime -sign默认使用SHA256withRSA,对应OID 1.2.840.113549.1.1.11,这是匹配的核心。
  2. 证书集合类型:将BerSet改为DerSet,OpenSSL生成的CMS中证书集合使用Der编码的Set,而非Ber编码。
  3. 明确DER编码:调用GetEncoded(Asn1Encodable.Der)确保输出严格是DER格式,和OpenSSL的-outform DER一致。
  4. 参数对应:SignerInfo的signedAttributes设为null,完全对应-noattr参数,避免额外属性干扰。

验证方法

你可以将生成的result和OpenSSL命令输出的文件做二进制对比,或者用openssl smime -verify -inform DER -in your-output.bin -noverify验证签名结构是否合法。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.01 20:04:54