Набор ключей не существует при попытке создать экземпляр нового RSACryptoServiceProvider.

Я пытаюсь автоматизировать развертывание сертификатов, включая управление разрешениями на закрытый ключ. Используя этот вопрос, я собрал код, который должен обновлять разрешения для сертификата:

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 "Набор ключей не существует".

По опыту я знаю, что обычно это означает, что текущий контекст безопасности не имеет разрешений на доступ к первичному ключу. Чтобы устранить эту возможность, я сделал следующее:

  1. Выясните, что представляет собой текущий пользователь, с помощью System.Security.Principal.WindowsIdentity.GetCurrent() в окне Immediate.
  2. Убедитесь, что у этого пользователя есть разрешение на полный доступ в оснастке MMC для сертификатов (и дважды проверьте, что я ищу для него нужное хранилище)
  3. Предоставлен полный доступ пользователю Everyone.
  4. Попытался создать объект CspParameters с KeyPassword и без него (вы можете увидеть его там в комментариях).

У меня нет идей. Сертификат является поддельным самозаверяющим тестовым сертификатом, поэтому это не вопрос отсутствия разрешений для других сертификатов в цепочке. Любая помощь будет оценена по достоинству.

ОБНОВИТЬ:

Я смог заставить этот код выполняться, изменив некоторые флаги для установки сертификата, который предшествует этому шагу. Теперь код выполняется, по-видимому, успешно, но никакого видимого эффекта я не вижу в MMC.


person Chris B. Behrens    schedule 16.02.2016    source источник


Ответы (1)


Я решил эту проблему, более или менее. Код для управления разрешениями, перечисленными выше, является надежным. Что было проблематичным, так это код для инициации сертификата перед его добавлением. Путь здравого смысла к этому выглядит так:

var certificate = new X509Certificate2(bytes, password);

Проблема с этим заключается в том, что закрытый ключ не сохраняется в хранилище, на что и опирается код разрешений (дух). Чтобы это произошло, вам нужно создать экземпляр сертификата, который будет добавлен в хранилище следующим образом:

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 и повторное открытие вызывает обновление, если вы сомневаетесь в том, что видите.

person Chris B. Behrens    schedule 17.02.2016
comment
Большое спасибо - это было именно то, что мне было нужно! - person jbsmith; 24.09.2016