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

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


在“即时”窗口中使用System.Security.Principal.WindowsIdentity.GetCurrent()找出当前用户是什么
确保用户在MMC管理单元中具有证书的“完全控制”权限(并再次确认我正在为其寻找合适的存储区)
授予对所有人用户的完全控制权限。
尝试创建带有和不带有KeyPassword的CspParameters对象(您可以在此处看到注释)。


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

更新:

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

最佳答案

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

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并重新打开会强制刷新。

08-17 20:21