【问题标题】:"Keyset does not exist" when trying to instantiate a new RSACryptoServiceProvider尝试实例化新的 RSACryptoServiceProvider 时出现“密钥集不存在”
【发布时间】:2016-05-28 01:10:51
【问题描述】:

我正在尝试自动部署证书,包括管理私钥的权限。使用这个question,我拼凑了一些应该更新证书权限的代码:

public static SetPermissionsResult SetPermissions(X509Certificate2 certificate, string userName)
{
    var account = new SecurityIdentifier(WellKnownSidType.NetworkServiceSid, null);

    using (var store = new X509Store(StoreName.My, StoreLocation.LocalMachine))
    {
        store.Open(OpenFlags.MaxAllowed);

        var newCertificate = store.Certificates.Find(X509FindType.FindBySerialNumber, certificate.SerialNumber, false)[0];

        var rsa = newCertificate.PrivateKey as RSACryptoServiceProvider;
        if (rsa == null)
        {
            return SetPermissionsResult.Failure;
        }

        rsa.PersistKeyInCsp = true;

        var cspParams = new CspParameters(
            rsa.CspKeyContainerInfo.ProviderType,
            rsa.CspKeyContainerInfo.ProviderName,
            rsa.CspKeyContainerInfo.KeyContainerName)
                            {
                                Flags =
                                    CspProviderFlags.UseExistingKey
                                    | CspProviderFlags.UseMachineKeyStore,
                                CryptoKeySecurity =
                                    rsa.CspKeyContainerInfo.CryptoKeySecurity,
                                KeyNumber = (int)rsa.CspKeyContainerInfo.KeyNumber/*,
                                KeyPassword = password*/
                            };

        cspParams.CryptoKeySecurity.AddAccessRule(
            new CryptoKeyAccessRule(account, CryptoKeyRights.GenericRead, AccessControlType.Allow));

        using (var rsa2 = new RSACryptoServiceProvider(cspParams))
        {
        }

        return SetPermissionsResult.Success;
    }
}

在读取using (var rsa2 = new RSACryptoServiceProvider(cspParams))(新的加密提供程序被实例化以保持新的访问规则)的行上,我得到一个CryptographicException "Keyset does not exist"

我从经验中知道,这通常意味着当前的安全上下文没有访问主键的权限。为了排除这种可能性,我做了以下事情:

  1. 通过“即时”窗口中的System.Security.Principal.WindowsIdentity.GetCurrent() 了解当前用户的身份
  2. 确保该用户在 MMC 管理单元中对证书具有完全控制权限(并仔细检查了我是否正在为它寻找正确的存储)
  3. 向所有人用户授予完全控制权。
  4. 尝试使用和不使用 KeyPassword 创建 CspParameters 对象(您可以在此处看到它的注释)。

我没有想法。该证书是伪造的自签名测试证书,因此与链中的其他证书缺少权限无关。任何帮助将不胜感激。

更新:

我已经能够通过在此步骤之前修改一些用于安装证书的标志来执行此代码。现在,代码执行成功了,但我在 MMC 中看不到任何效果。

【问题讨论】:

    标签: c# cryptography acl continuous-deployment certificate-store


    【解决方案1】:

    我或多或少地解决了这个问题。上面列出的管理权限的代码是正确的。有问题的是在添加证书之前启动证书的代码。对此的常识方法如下所示:

    var certificate = new X509Certificate2(bytes, password);
    

    这样做的问题是它不会导致私钥在存储中持久化,这是权限代码所依赖的(duh)。要导致这种情况发生,您需要像这样实例化要添加到存储中的证书:

    var certificate = new X509Certificate2(bytes, "password123", X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);
    

    并像这样添加它:

    using (var store = new X509Store(storeName, StoreLocation.LocalMachine))
    {
           store.Open(OpenFlags.MaxAllowed);
    
           store.Add(certificate);
    }
    

    最后一点:MMC 管理单元在显示更新的权限方面是有风险的,即,即使它们实际上已经更改,它也可能不会显示新的权限。我达到了一个地步,我的一切工作都完美无缺,但我没有意识到这一点,因为 MMC 向我展示了不同的东西。如果您怀疑所看到的内容,则关闭 MMC 并重新打开会强制刷新。

    【讨论】:

    • 非常感谢 - 这正是我所需要的!
    猜你喜欢
    • 2021-08-06
    • 1970-01-01
    • 2013-10-24
    • 1970-01-01
    • 2016-07-06
    • 1970-01-01
    • 1970-01-01
    • 2015-12-20
    • 2017-03-13
    相关资源
    最近更新 更多