尝试实例化新的RSACryptoServiceProvider时“键集不存在”

时间:2016-02-16 16:32:34

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

我正在尝试自动部署证书,包括管理私钥的权限。使用此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不存在”

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

  1. 在立即窗口
  2. 中找出当前用户对System.Security.Principal.WindowsIdentity.GetCurrent()的看法
  3. 确保该用户在证书的MMC管理单元中具有完全控制权限(并仔细检查我正在查找正确的商店)
  4. 授予Everyone用户完全控制权。
  5. 尝试使用和不使用KeyPassword创建CspParameters对象(您可以看到它在那里注释)。
  6. 我没有想法。该证书是一个虚假的自签名测试证书,因此这不是链中缺少权限的其他证书的问题。任何帮助将不胜感激。

    更新:

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

1 个答案:

答案 0 :(得分:3)

我或多或少地解决了这个问题。上面列出的管理权限的代码是合理的。有问题的是在添加证书之前填写证书的代码。常识的方式如下:

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并重新开启,如果您怀疑自己所看到的内容,请重新启动。