EnvelopedCms如何正确识别要解密的证书而不是请求密码?

问题描述 投票:0回答:1

我正在解密电子邮件中的SMIME.P7M附件。我目前有以下内容

                EnvelopedCms envDate = new EnvelopedCms(new ContentInfo(data));
                envDate.Decode(data);
                RecipientInfoCollection recips = envDate.RecipientInfos;
                RecipientInfo recipin = recips[0];
                X509Certificate2 x509_2 = LoadCertificate2(StoreLocation.CurrentUser, (SubjectIdentifier)recipin.RecipientIdentifier);

负载证书看起来像这样

public static X509Certificate2 LoadCertificate2(StoreLocation storeLocation, SubjectIdentifier identifier)
        {
            X509Store store = new X509Store(storeLocation);
            store.Open(OpenFlags.ReadOnly);
            X509Certificate2Collection certCollection = store.Certificates;
            X509Certificate2 x509 = null;
            X509IssuerSerial issuerSerial;

            if (identifier.Type == SubjectIdentifierType.IssuerAndSerialNumber)
            {
                issuerSerial = (X509IssuerSerial)identifier.Value;
            }

            foreach (X509Certificate2 c in certCollection)
            {
                Console.WriteLine("{0}Valid Date: {1}{0}", Environment.NewLine, c.NotBefore);
                if (c.SerialNumber == issuerSerial.SerialNumber && c.Issuer == issuerSerial.IssuerName)
                {
                    x509 = c;
                    break;
                }
            }
            if (x509 == null)
                Console.WriteLine("A x509 certificate for  was not found");
            store.Close();
            return x509;
        }

以上代码只获取第一个收件人RecipientInfo recipin = recips [0];然而,获取相应证书以循环每个收件人并检查商店是否为SubjectIdentifier是最有效的方法?

一旦获得正确的证书,我就用它

                X509Certificate2Collection col = new X509Certificate2Collection(x509_2);
                envDate.Decrypt(col);
               decData = envDate.ContentInfo.Content;

这会提示输入与证书私钥相关联的PIN,如何在调用解密之前添加PIN,这样就没有提示?

encryption certificate x509certificate smime
1个回答
0
投票

.NET Framework中的EnvelopedCms类没有任何方法可以让您轻松地以编程方式应用PIN(或其他解锁机制);特别是如果证书存在于CurrentUser \ My或LocalMachine \ My商店中(因为这些证书在extraStore集合中的任何证书之前被搜索)。

在.NET Framework 4.7+上,如果证书不在CurrentUser \ My或LocalMachine \ My商店中,您可以以非常迂回的方式完成CNG可访问密钥:

CngKey key = ExerciseLeftToTheReader();
key.SetProperty(new CngProperty("SmartCardPin", pin, CngPropertyOptions.None));
X509Certificate2 cert = DifferentExerciseLeftToTheReader();

// You need to use tmpCert because this won't do good things if the certificate
// already knows about/how-to-find its associated private key

using (key)
using (X509Certificate2 tmpCert = new X509Certificate2(cert.RawData))
{
   // Need to NOT read the HasPrivateKey property until after the property set.  Debugger beware.
   NativeMethods.CertSetCertificateContextProperty(
       tmpCert.Handle,
       CERT_NCRYPT_KEY_HANDLE_PROP_ID,
       CERT_SET_PROPERTY_INHIBIT_PERSIST_FLAG,
       key.Handle);

   envelopedCms.Decrypt(new X509Certificate2Collection(tmpCert));
}

(当然,您需要为CertSetCertificateContextProperty定义P / Invoke)

在.NET Core 3.0中,这变得更容易(预览2目前可用于此功能)...虽然它确实让您负担确定哪个RecipientInfo,以及哪个密钥随之而来:

RecipientInfo recipientInfo = FigureOutWhichOneYouCanMatch();
CngKey key = ExerciseLeftToTheReader();
key.SetProperty(new CngProperty("SmartCardPin", pin, CngPropertyOptions.None));

using (key)
using (RSA rsa = new RSACng(key))
{
    envelopedCms.Decrypt(recipientInfo, rsa);
}
© www.soinside.com 2019 - 2024. All rights reserved.