【问题标题】:Keyset does not exist although the PrivateKey is set尽管设置了 PrivateKey,但 Keyset 不存在
【发布时间】:2021-01-18 04:26:50
【问题描述】:

我正在尝试使用 CmsSigner 签署消息并附加 X509 证书:

public static byte[] Sign(X509Certificate2 certificate, string keyXml)
{
    ContentInfo contentInfo = new ContentInfo(new Oid("1.2.840.113549.1.7.1"), Encoding.ASCII.GetBytes("hello"));

    RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
    rsa.FromXmlString(keyXml);

    using (certificate.GetRSAPrivateKey())
    {
        certificate.PrivateKey = rsa;
    }
    var signer = new CmsSigner(certificate);

    signer.DigestAlgorithm = new Oid("2.16.840.1.101.3.4.2.1");
    signer.SignedAttributes.Add(new Pkcs9SigningTime());

    var signedCms = new SignedCms(contentInfo, false);
    signedCms.ComputeSignature(signer);
    var encodeByteBlock = signedCms.Encode();
    return encodeByteBlock;
}

证书没有密钥(HasPrivateKeyfalse)所以我使用使用 OpenSSL 生成的正确密钥设置它:

openssl req -new -sha256 -x509 -days 7300 -out ca.crt -keyout ca.key.pem -nodes

我将 ca.key.pem 转换为 XML。

但是当ComputeSignature被调用时,抛出了这个异常:

System.Security.Cryptography.CryptographicException: '密钥集没有 存在'

堆栈跟踪:

在 System.Security.Cryptography.Pkcs.PkcsUtils.CreateSignerEncodeInfo(CmsSigner 签名者,布尔静默,SafeCryptProvHandle& hProv)在 System.Security.Cryptography.Pkcs.SignedCms.Sign(CmsSigner 签名者, 布尔无声)在 System.Security.Cryptography.Pkcs.SignedCms.ComputeSignature(CmsSigner 签名者,布尔无声)在 System.Security.Cryptography.Pkcs.SignedCms.ComputeSignature(CmsSigner 签名者)在 ConsoleTest472.Program.Sign(X509Certificate2 证书,字符串 keyXml) 在 D:\me\Projects\ConsoleTest472\ConsoleTest472\Program.cs:第 56 行 ConsoleTest472.Program.Main(String[] args) 在 D:\me\Projects\ConsoleTest472\ConsoleTest472\Program.cs:第 63 行

我使用的代码有什么问题? keyset 不是在私钥设置的时候设置的吗?

【问题讨论】:

    标签: c# cryptography certificate rsa x509certificate


    【解决方案1】:

    我使用的代码有什么问题?

    using (certificate.GetRSAPrivateKey())
    {
        certificate.PrivateKey = rsa;
    }
    

    没有多大意义。您正在获取私钥,然后忽略它,尝试替换它,然后丢弃它。

    更好的版本是

    var signedCms = new SignedCms(contentInfo, false);
    
    using (X509Certificate2 certWithKey = certificate.CopyWithPrivateKey(rsa))
    {
        var signer = new CmsSigner(certWithKey);
    
        signer.DigestAlgorithm = new Oid("2.16.840.1.101.3.4.2.1");
        signer.SignedAttributes.Add(new Pkcs9SigningTime());
    
        signedCms.ComputeSignature(signer);
    }
    
    var encodeByteBlock = signedCms.Encode();
    return encodeByteBlock;
    

    将私钥绑定到证书副本(而不是进行突变)的工作,以及完成这项工作所需的一切(在这种情况下,它最终会用一个替换 RSACryptoServiceProvider 密钥) RSACng 密钥,因为平台仅支持 CNG 用于仅内存(临时)密钥)。

    【讨论】:

    • 我知道我的代码没有意义,但是当 PrivateKey 设置为 RSACryptoServiceProvider 对象且 HasPrivateKey 为 true 时,为什么找不到密钥集?跨度>
    • 它可以表示“这是一个内存密钥,但我需要一个命名密钥”或“这个密钥只有公钥信息,但我需要私钥”,或者“嗯,这个密钥应该存储在一个文件中,但该文件丢失了”。在您的情况下,我认为它说“我是一个名为 NULL 的持久键”,然后负载返回为“我找不到没有名称的键......”。你不应该使用 PrivateKey setter,并且应该避免使用它的 getter。
    【解决方案2】:

    私钥必须是:

    • 在执行代码的用户的MY Key Store 中
    • 在机器的MY Key Store 中,授予用户权限
    • 与证书一起存储在 PFX/PKCS#12 文件中,并作为 X509Certificate2 加载并使用密码保护它。

    【讨论】:

      猜你喜欢
      • 2016-01-31
      • 2014-06-17
      • 2017-09-29
      • 1970-01-01
      • 2011-09-04
      • 1970-01-01
      • 2018-10-24
      • 2023-03-14
      • 2018-11-27
      相关资源
      最近更新 更多