我正在使用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_mode:pss
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_decunsigned.zip
我试过了,但得到了异常System.NotSupportedException:"SQLite在pkcs7上不可用。验证(原始(行
public byte[] Verify(byte[] data, byte[] signCert, byte[] privateKey)
{
bool valid = false;
// 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);
MimeMessage message = MimeMessage.Load(new MemoryStream(data));
// Create BouncyCastle Secure MimeContext
MimeEntity original;
ApplicationPkcs7Mime pkcs7 = message.Body as ApplicationPkcs7Mime;
if (pkcs7 != null && pkcs7.SecureMimeType == SecureMimeType.SignedData)
{
foreach (var signature in pkcs7.Verify(out original))
{
try
{
valid = signature.Verify();
}
catch (DigitalSignatureVerifyException)
{
// There was an error verifying the signature.
}
}
}
byte[] res = { 0 };
return res;
}
有没有什么指南可以让我验证并将数据返回到它的原始论坛,或者举个例子?
默认情况下,MimeKit尝试基于其用于证书存储的SQLite后端实例化S/MIME验证上下文。
如果您没有安装SQLite和/或证书没有存储在MimeKit将为您维护的SQLite数据库中,那么您需要注册一个不同的后端来存储/检索证书,或者实例化您自己的S/MIME上下文(就像您为签名所做的那样(。
MimeKit有两个选项:
- TemporarySecureMimeContext,它将证书存储在内存中,并且是您在上面的代码片段中用于对消息进行签名的内容
- 使用Windows操作系统X.509证书存储的WindowsSecureMimeContext
一旦您决定使用其中的哪一个,您将需要将证书导入上下文(上下文将把证书导入到适当的后端存储位置(。
然后,在那之后,你可以这样做:
using (BouncyCastleSecureMimeContext ctx = new TemporarySecureMimeContext()) {
ctx.Import (...);
foreach (var signature in pkcs7.Verify(ctx, out original)) {
// ...
}
}
更新:
这导致了对openssl cms sign命令的滥用,以及无法使用MimeKit验证签名,因为MimeKit希望封装的签名数据按照S/MIME规范采用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 sign ...
(对内容进行签名时,它会生成如下内容:
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格式。