如何用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,对应OID1.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);
关键修正点说明
- 签名算法OID修正:原代码使用
PkcsObjectIdentifiers.RsaEncryption(仅RSA加密),但OpenSSL的smime -sign默认使用SHA256withRSA,对应OID1.2.840.113549.1.1.11,这是匹配的核心。 - 证书集合类型:将BerSet改为DerSet,OpenSSL生成的CMS中证书集合使用Der编码的Set,而非Ber编码。
- 明确DER编码:调用
GetEncoded(Asn1Encodable.Der)确保输出严格是DER格式,和OpenSSL的-outform DER一致。 - 参数对应:
SignerInfo的signedAttributes设为null,完全对应-noattr参数,避免额外属性干扰。
验证方法
你可以将生成的result和OpenSSL命令输出的文件做二进制对比,或者用openssl smime -verify -inform DER -in your-output.bin -noverify验证签名结构是否合法。
内容的提问来源于stack exchange,提问作者LightningRider
相关产品推荐
相关产品推荐

