C# 使用MimeKit对cms进行签名和验证
我正在使用Mimekit做rsa pss cms签名,来模拟这个openssl命令 openssl cms-sign-in keys.zip-binary-nodetach-signer selfsigned.crt-inkey keypair.pem-out keys.zip.signed-keyopt rsa_padding_模式:pssC# 使用MimeKit对cms进行签名和验证,c#,bouncycastle,mimekit,C#,Bouncycastle,Mimekit,我正在使用Mimekit做rsa pss cms签名,来模拟这个openssl命令 openssl cms-sign-in keys.zip-binary-nodetach-signer selfsigned.crt-inkey keypair.pem-out keys.zip.signed-keyopt rsa_padding_模式:pss public byte[] Sign(byte[] data, byte[] signCert, byte[] privateKey, CmsKe
public byte[] Sign(byte[] data, byte[] signCert, byte[] privateKey, CmsKeyOpt cmsKeyOpt)
{
MimeMessage message = new MimeMessage
{
Body = new MimePart()
{
Content = new MimeContent(new MemoryStream(data)),
ContentTransferEncoding = ContentEncoding.Binary,
},
};
// Load private key from byte array
StreamReader stream = new StreamReader(new MemoryStream(privateKey), Encoding.Default);
AsymmetricCipherKeyPair keyPair = (AsymmetricCipherKeyPair)new PemReader(stream).ReadObject();
// load certifacte from byte array
X509CertificateParser parser = new X509CertificateParser();
X509Certificate certificate = parser.ReadCertificate(signCert);
// Create RSA PSS CMS signer
CmsSigner signer = new CmsSigner(certificate, keyPair.Private)
{
RsaSignaturePadding = RsaSignaturePadding.Pss,
DigestAlgorithm = DigestAlgorithm.Sha256,
};
// Create BouncyCastle Secure MimeContext
BouncyCastleSecureMimeContext ctx = new TemporarySecureMimeContext();
ctx.EncapsulatedSign(signer, new MemoryStream(data));
// Get signed message body and override it
message.Body = MultipartSigned.Create(ctx, signer, message.Body);
byte[] singedData;
using (var memory = new MemoryStream())
{
message.WriteTo(memory);
singedData = memory.ToArray();
}
return singedData;
}
一切正常,我的问题是如何通过Mimekit/BouncyCastle实现验证,以模拟这个openssl命令
openssl cms-verify-in keys.zip.signed.dec-CAfile selfsigned.crt-out keys\u dec\u unsigned.zip
我尝试了这个方法,但得到了异常System.NotSupportedException:“SQLite在pkcs7上不可用。请验证(原始)行
是否有任何我可以遵循的指南来验证数据并将其返回到其原始论坛,或者举个例子?默认情况下,MimeKit尝试基于其SQLite后端实例化s/MIME验证上下文以用于证书存储 如果没有安装SQLite和/或没有将证书存储在MimeKit将为您维护的SQLite数据库中,那么您需要为证书存储/检索注册不同的后端,或者实例化您自己的S/MIME上下文(就像您为签名所做的那样) MimeKit具有两个选项:
- 它将证书存储在内存中,并且是您用来在上面的代码段中对消息进行签名的
- 它使用Windows OS X.509证书存储
using (BouncyCastleSecureMimeContext ctx = new TemporarySecureMimeContext()) {
ctx.Import (...);
foreach (var signature in pkcs7.Verify(ctx, out original)) {
// ...
}
}
更新:
这导致了openssl cms sign命令的误用,以及无法使用MimeKit验证签名,因为MimeKit希望封装的签名数据采用MIME格式,因为它应该符合S/MIME规范
交易如下:
openssl cms sign命令可用于对任意数据进行签名,相应的openssl cms verify命令可用于验证此类签名输出。但是,只有当openssl cms sign命令签名的原始内容是MIME格式时,它才是有效的S/MIME
MimeKit需要有效的S/MIME,因为它是。。。惊喜,惊喜。。。MIME库
您可能已经注意到,Verify()方法有一个输出参数(out MimeEntity originalEntity
)。这意味着Verify()方法从签名数据中提取封装的内容,并将其解析为MIME实体,然后以所述输出参数的形式将其返回给调用方
如果封装的内容不是MIME格式,那么很明显,解析器将无法解析它
CMS签名工作原理的其他背景:
当您使用CMS签名例程(例如,openssl CMS签名…
)对内容进行签名时,它会生成类似以下内容的内容:
MIME-Version: 1.0
Content-Disposition: attachment; filename="smime.p7m"
Content-Type: application/pkcs7-mime; smime-type=signed-data; name="smime.p7m"
Content-Transfer-Encoding: base64
MIIQgAYJKoZIhvcNAQcCoIIQcTCCEG0CAQExDTALBglghkgBZQMEAgEwggkPBgkq...
上述MIME部分中的base64内容包括原始内容和CMS签名数据(即签名列表)
因此,MimeKit的Verify()方法需要在base64解码后将签名与原始内容分离。然后,MimeKit将返回给您、调用者、原始内容(它希望是MIME格式)和签名列表,然后您可以独立验证签名的真实性
当我不断地重复自己,当你签署内容时,
file.bin
文件的格式很重要,我并不是说openssl或MimeKit在验证签名时需要解析file.bin
,我是说,file.bin
的内容与从openssl cms sign生成的S/MIME输出中的base64 blob中提取的内容完全相同…,因此,它需要采用MIME格式。是的,你是对的,我实现了它,但它给了我另一个异常,即System.FormatException:未能解析pkcs7.Verify(ctx,out original)中的实体头。知道我已经用上面的openssl命令生成了签名文件后,请以任何方式链接到我的代码。为什么会发生这种情况?因为签名数据不是应该的MIME?当我用问题中提到的openssl命令生成签名数据时,如何会发生这种情况,这是OpenSSLMIME版本签署文件的第一部分:1.0内容配置:附件;filename=“smime.p7m”内容类型:application/pkcs7 mime;smime类型=有符号数据;name=“smime.p7m”内容传输编码:base64 miiqgayjkozihvcnaqccoiqctcceg0caqexdtalbglghkgbzqmeagewggpbgkq。。。。
MIME-Version: 1.0
Content-Disposition: attachment; filename="smime.p7m"
Content-Type: application/pkcs7-mime; smime-type=signed-data; name="smime.p7m"
Content-Transfer-Encoding: base64
MIIQgAYJKoZIhvcNAQcCoIIQcTCCEG0CAQExDTALBglghkgBZQMEAgEwggkPBgkq...