"Указан неверный тип провайдера" CryptographicException при попытке загрузить закрытый ключ сертификата

Я пытаюсь прочитать закрытый ключ сертификата, который был предоставлен мне сторонним поставщиком услуг, поэтому я могу использовать его для шифрования некоторого XML-кода перед его отправкой по беспроводной сети. Я делаю это программно в C#, но я думаю, что это проблема с разрешениями или неправильной настройкой, поэтому я сосредоточусь на фактах, которые кажутся наиболее актуальными:

  • Я не думаю, что эта проблема связана с кодом; мой код работает на других компьютерах, и проблема затрагивает пример кода от Microsoft.
  • Сертификат был предоставлен в виде файла PFX и предназначен только для тестирования, поэтому он также включает в себя фиктивный центр сертификации.
  • Используя MMC.exe, я могу импортировать сертификат в персональное хранилище для локального компьютера, прежде чем предоставлять разрешения на закрытый ключ всем соответствующим учетным записям и перетаскивать центр сертификации в доверенные корневые центры сертификации.
  • Используя C#, я могу загрузить сертификат (идентифицированный по его отпечатку) и проверить, что у него есть закрытый ключ, используя X509Certificate2.HasPrivateKey, Однако попытка прочитать ключ вызывает ошибку. В.NET CryptographicException выдается с сообщением "Указан неверный тип провайдера" при попытке получить доступ к свойству X509Certificate2.PrivateKey, В Win32 вызывается метод CryptAcquireCertificatePrivateKey возвращает эквивалент HRESULT, NTE_BAD_PROV_TYPE,
  • Это то же исключение, которое также возникает при использовании двух собственных примеров кода Microsoft для чтения закрытого ключа сертификата.
  • Установка того же сертификата в эквивалентное хранилище для текущего пользователя вместо локального компьютера позволяет успешно загрузить закрытый ключ.
  • Я на Windows 8.1 с правами локального администратора, и я попытался запустить мой код в обычном и повышенном режимах. Коллеги в Windows 7 и Windows 8 смогли загрузить ключ из локального хранилища компьютеров для того же сертификата.
  • Я могу успешно прочитать закрытый ключ самозаверяющего сертификата IIS, который находится в том же хранилище.
  • Я уже нацеливаюсь на.NET 4.5 (об этой ошибке сообщалось в некоторых старых версиях фреймворка).
  • Я не думаю, что это проблема с шаблонами сертификатов, потому что я ожидаю, что это повлияет как на локальный компьютер, так и на хранилища текущего пользователя в равной степени?

В отличие от моих коллег, я несколько раз пытался удалить и переустановить сертификат различными способами, в том числе с помощью диспетчера IIS, а также с использованием более старого сертификата того же издателя. Я не вижу следов старых или дублирующих сертификатов в MMC. Однако у меня есть много файлов с закрытым ключом одинакового размера, которые, исходя из времени последней записи, должны были остаться после моих различных попыток установки. Они находятся в следующих местах для локального компьютера и текущего хранилища пользователей соответственно:

C: \ ProgramData \ Microsoft \ Crypto \ RSA \ MachineKeys

c: \ Users \\ AppData \ Roaming \ Microsoft \ Crypto \ RSA \ S-1-5-21- [оставшийся идентификатор пользователя]

Итак, кто-нибудь может посоветовать, пожалуйста:

  • Рекомендуется удалить сертификат с помощью MMC, удалить все файлы, которые выглядят как потерянные закрытые ключи, а затем переустановить сертификат и повторить попытку?
  • Есть ли другие файлы, которые я должен попытаться удалить вручную?
  • Есть что-нибудь еще, что я должен попробовать?

ОБНОВЛЕНИЕ - Добавлен пример кода, показывающий попытку чтения закрытого ключа:

static void Main()
{
    // Exception occurs when trying to read the private key after loading certificate from here:
    X509Store store = new X509Store("MY", StoreLocation.LocalMachine);
    // Exception does not occur if certificate was installed to, and loaded from, here:
    //X509Store store = new X509Store("MY", StoreLocation.CurrentUser);

    store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);

    X509Certificate2Collection collection = (X509Certificate2Collection)store.Certificates;
    X509Certificate2Collection fcollection = (X509Certificate2Collection)collection.Find(X509FindType.FindByTimeValid, DateTime.Now, false);
    X509Certificate2Collection scollection = X509Certificate2UI.SelectFromCollection(fcollection, "Test Certificate Select", "Select a certificate from the following list to get information on that certificate", X509SelectionFlag.MultiSelection);
    Console.WriteLine("Number of certificates: {0}{1}", scollection.Count, Environment.NewLine);

    foreach (X509Certificate2 x509 in scollection)
    {
        try
        {
            Console.WriteLine("Private Key: {0}", x509.HasPrivateKey ? x509.PrivateKey.ToXmlString(false) : "[N/A]");
            x509.Reset();
        }
        catch (CryptographicException ex)
        {
            Console.WriteLine(ex.Message);
        }
    }
    store.Close();

    Console.ReadLine();
}

21 ответ

У меня была та же проблема на Windows 8 и Server 2012/2012 R2 с двумя новыми сертификатами, которые я недавно получил. В Windows 10 проблема больше не возникает (но это не помогает мне, поскольку код, управляющий сертификатом, используется на сервере). Хотя решение Джо Строммена в принципе работает, другая модель закрытого ключа потребует значительных изменений в коде с использованием сертификатов. Я считаю, что лучшим решением является преобразование закрытого ключа из CNG в RSA, как объяснил здесь Реми Блок.

Реми использует OpenSSL и два более старых инструмента для выполнения преобразования закрытого ключа, мы хотели автоматизировать его и разработали решение только для OpenSSL. Дано MYCERT.pfx с паролем закрытого ключа MYPWD в формате CNG, это шаги, чтобы получить новый CONVERTED.pfx с закрытым ключом в формате RSA и тем же паролем:

  1. Извлечение открытых ключей, полная цепочка сертификатов:

OpenSSL pkcs12 -in "MYCERT.pfx" -nokeys -out "MYCERT.cer" -passin "pass:MYPWD"

  1. Извлечь закрытый ключ:

OpenSSL pkcs12 -in "MYCERT.pfx" -nocerts –out “MYCERT.pem" -passin "pass:MYPWD" -passout "pass:MYPWD"

  1. Преобразовать закрытый ключ в формат RSA:

OpenSSL rsa -inform PEM -in "MYCERT.pem" -out "MYCERT.rsa" -passin "pass:MYPWD" -passout "pass:MYPWD"

  1. Объединить открытые ключи с закрытым ключом RSA в новый PFX:

OpenSSL pkcs12 -export -in "MYCERT.cer" -inkey "MYCERT.rsa" -out "CONVERTED.pfx" -passin "pass:MYPWD" -passout "pass:MYPWD"

Если вы загрузите преобразованный файл pfx или импортируете его в хранилище сертификатов Windows вместо формата pgx CNG, проблема исчезнет, ​​и код C# не нужно менять.

Одна дополнительная ошибка, с которой я столкнулся при автоматизации этого: мы используем длинные сгенерированные пароли для закрытого ключа, и пароль может содержать ". Для командной строки OpenSSL" символы внутри пароля должны быть экранированы как "".

В моем случае я пытался использовать самозаверяющий сертификат с командой PowerShell New-SelfSignedCertificate. По умолчанию он генерирует сертификат с использованием API CNG (Crypto-Next Generation) вместо старого / классического крипто-CAPI. Некоторые старые части кода будут иметь проблемы с этим; в моем случае это была более старая версия поставщика IdentityServer STS.

Добавив это в конце моей команды New-SelfSignedCertificate, я решил эту проблему:

KeyExchange

Ссылка на переключатель для команды powershell:

https://docs.microsoft.com/en-us/powershell/module/pkiclient/new-selfsignedcertificate?view=win10-ps

Вот еще одна причина, по которой это может произойти, это была странная проблема, и после одного дня борьбы я решил ее. В качестве эксперимента я изменил разрешение для папки "C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys", в которой хранятся данные закрытого ключа для сертификатов с использованием хранилища ключей компьютеров. При изменении разрешения для этой папки все частные ключи отображаются как "Поставщик Microsoft Software KSP", который не является поставщиком (в моем случае они должны быть "Поставщиком криптографии Schannel Microsoft RSA").

Решение: сбросьте разрешения для папки Machine key s

Оригинальное разрешение для этой папки можно найти здесь. В моем случае я изменил разрешение для "Все", дал разрешения на чтение, где он снял галочку "Специальные разрешения". Поэтому я проверил с одним из членов моей команды (щелкните правой кнопкой мыши по папке> Свойства> Безопасность> Дополнительно> выберите "Все"> Изменить> Нажмите "Дополнительные параметры" в списке разрешений флажок

Специальные разрешения

Надеюсь, это спасет чей-то день!

Здесь, где я нашел источник ответа, ему за это отдают должное.

В моем случае следующий код работал локально (как NET 3.5, так и NET 4.7):

 var certificate = new X509Certificate2(certificateBytes, password);

 string xml = "....";
 XmlDocument xmlDocument = new XmlDocument();
 xmlDocument.PreserveWhitespace = true;
 xmlDocument.LoadXml(xml);

 SignedXml signedXml = new SignedXml(xmlDocument);
 signedXml.SigningKey = certificate.PrivateKey;

 //etc...

Но это не удалось при развертывании в веб-приложении Azure на certificate.PrivateKey

Это сработало, изменив код следующим образом:

 var certificate = new X509Certificate2(certificateBytes, password, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
                                                                   //^ Here
 string xml = "....";
 XmlDocument xmlDocument = new XmlDocument();
 xmlDocument.PreserveWhitespace = true;
 xmlDocument.LoadXml(xml);

 SignedXml signedXml = new SignedXml(xmlDocument);
 signedXml.SigningKey = certificate.GetRSAPrivateKey();
                                      // ^ Here too

 //etc...

Целый день работы, потерянной благодаря Microsoft Azure, снова в моей жизни.

Что сработало для меня: IIS / Пул приложений / Загрузить профиль пользователя = true

Ссылка на блог Алехандро является ключевой.

Я полагаю, что это потому, что сертификат хранится на вашем компьютере с API CNG ("Crypto Next-Generation"). Старый API.NET не совместим с ним, поэтому он не работает.

Вы можете использовать оболочку Security.Cryptography для этого API ( доступно на Codeplex). Это добавляет методы расширения X509Certificate/X509Certificate2поэтому ваш код будет выглядеть примерно так:

using Security.Cryptography.X509Certificates; // Get extension methods

X509Certificate cert; // Populate from somewhere else...
if (cert.HasCngKey())
{
    var privateKey = cert.GetCngPrivateKey();
}
else
{
    var privateKey = cert.PrivateKey;
}

К сожалению, объектная модель для закрытых ключей CNG несколько отличается. Я не уверен, что вы можете экспортировать их в XML, как в исходном примере кода... в моем случае мне просто нужно было подписать некоторые данные с помощью закрытого ключа.

Как указывалось во многих других ответах, эта проблема возникает, когда закрытым ключом является ключ Windows Cryptography: Next Generation (CNG) вместо "классического" ключа Windows Cryptographic API (CAPI).

Начиная с.NET Framework 4.6 доступ к закрытому ключу (при условии, что это ключ RSA) можно получить с помощью метода расширения в X509Certificate2: cert.GetRSAPrivateKey(),

Когда CNG хранит закрытый ключ, GetRSAPrivateKey метод расширения вернет RSACng объект (новый для фреймворка в 4.6). Поскольку CNG имеет проход для чтения старых программных ключей CAPI, GetRSAPrivateKey обычно возвращает RSACng даже для ключа CAPI; но если CNG не может его загрузить (например, это ключ HSM без драйвера CNG), тогда GetRSAPrivateKey вернет RSACryptoServiceProvider,

Обратите внимание, что тип возвращаемого значения для GetRSAPrivateKey является RSA, Начиная с.NET Framework v4.6, вам не нужно выходить за рамки RSA для стандартных операций; единственная причина использовать RSACng или же RSACryptoServiceProvider когда вам нужно взаимодействовать с программами или библиотеками, которые используют NCRYPT_KEY_HANDLE или идентификатор ключа (или открытие постоянного ключа по имени). (В.NET Framework v4.6 было много мест, которые все еще приводят объект ввода к RSACryptoServiceProvider, но все они были устранены с помощью 4.6.2 (конечно, это более 2 лет назад на данный момент)).

Поддержка сертификата ECDSA была добавлена ​​в 4.6.1 через GetECDsaPrivateKey метод расширения, и DSA был обновлен в 4.6.2 через GetDSAPrivateKey,

На.NET Core возвращаемое значение из Get[Algorithm]PrivateKey меняется в зависимости от ОС. Для RSA это RSACng/RSACryptoServiceProvider в Windows, RSAOpenSsl в Linux (или любой UNIX-подобной ОС, кроме macOS) и непубличный тип в macOS (то есть вы не можете разыграть его за пределами RSA).

Используя Visual Studio 2019 и IISExpress, я смог исправить эту проблему, удалив следующий флаг при загрузке .pfx|.p12 файл:

X509KeyStorageFlags.MachineKeySet

Перед:

X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable

После:

X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable

Обычно я загружаю сертификат таким образом:

var myCert = new X509Certificate2("mykey.pfx", "mypassword", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);

Это НЕ вызывает исключение, вместо этого возникает исключение при попытке использовать сертификат (или, в моем случае, при попытке получить .PrivateKey). Я обнаружил, что эта проблема может быть вызвана тем, что у вызывающего пользователя недостаточно прав.

Поскольку я полагаюсь на MachineKeySetflag для некоторых сред, мое текущее решение - проглотить исключение, изменить флаги и повторить попытку.:/

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

ПРИМЕЧАНИЕ..pfx файл, который я использую, был создан с веб-сайта, который использует библиотеку JavaScript (digitalbazaar/forge), который НЕ использует поставщиков хранилища ключей CNG (криптография следующего поколения). вот много распространенных причин этой ошибки (наиболее частые исправления, связанные сCNGрасширения, которые, к сожалению, даже изменили пространства имен в версиях.NET), которые вызывают ту же ошибку. В конечном итоге Microsoft должна быть более многословной при выдаче таких ошибок.

Я пробовал все в этом посте, но для меня решение было:

  1. Импортируйте исходный файл.p12 на мою локальную машину
  2. Экспортируйте его как файл.pfx, отметив параметры "Экспортировать все расширенные свойства" и "Включить все сертификаты в путь сертификации, если это возможно".
  3. Прочтите новый сертификат, используя параметры этого флага из этого решения для публикации:

    var certificate = new X509Certificate2(certKeyFilePath, passCode,
    X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet |       
    X509KeyStorageFlags.PersistKeySet );
    

Версия ответа Powershell от @berend-engelbrecht, предполагая openssl устанавливается через шоколад

function Fix-Certificates($certPasswordPlain)
{
    $certs = Get-ChildItem -path "*.pfx" -Exclude "*.converted.pfx"
    $certs | ForEach-Object{
        $certFile = $_

        $shortName = [io.path]::GetFileNameWithoutExtension($certFile.Name)
        Write-Host "Importing $shortName"
        $finalPfx = "$shortName.converted.pfx"


        Set-Alias openssl "C:\Program Files\OpenSSL\bin\openssl.exe"

        # Extract public key
        OpenSSL pkcs12 -in $certFile.Fullname -nokeys -out "$shortName.cer" -passin "pass:$certPasswordPlain"

        # Extract private key
        OpenSSL pkcs12 -in $certFile.Fullname -nocerts -out "$shortName.pem" -passin "pass:$certPasswordPlain" -passout "pass:$certPasswordPlain"

        # Convert private key to RSA format
        OpenSSL rsa -inform PEM -in "$shortName.pem" -out "$shortName.rsa" -passin "pass:$certPasswordPlain" -passout "pass:$certPasswordPlain" 2>$null

        # Merge public keys with RSA private key to new PFX
        OpenSSL pkcs12 -export -in "$shortName.cer" -inkey "$shortName.rsa" -out $finalPfx -passin "pass:$certPasswordPlain" -passout "pass:$certPasswordPlain"

        # Clean up
        Remove-Item "$shortName.pem"
        Remove-Item "$shortName.cer"
        Remove-Item "$shortName.rsa"

        Write-Host "$finalPfx created"
    }
}

# Execute in cert folder
Fix-Certificates password

У меня тоже была эта проблема и после попытки внесения предложений в этот пост безуспешно. Я смог решить свою проблему, перезагрузив сертификат с помощью утилиты сертификатов Digicert https://www.digicert.com/util/. Это позволяет выбрать провайдера для загрузки сертификата. В моем случае загрузка сертификата в провайдер криптографических провайдеров Microsoft RSA Schannel, где я ожидал, что он будет в первую очередь, решает проблему.

Что свойства PrivateKey и ОткрытыйКлючи устарел, начинающиеся с NET 4.6. Пожалуйста, используйте:

  • сертификат.GetRSAPrivateKey() или GetECDsaPrivateKey()
  • сертификат.GetRSAPublicKey() или GetECDsaPublicKey()

С уважением

Я столкнулся с той же проблемой в нашем приложении IIS:

 System.Security.Cryptography.Pkcs.PkcsUtils.CreateSignerEncodeInfo(CmsSigner signer, Boolean silent)
    System.Security.Cryptography.Pkcs.SignedCms.Sign(CmsSigner signer, Boolean silent)
    System.Security.Cryptography.Pkcs.SignedCms.ComputeSignature(CmsSigner signer, Boolean silent)

Регенерирование сертификатов, как упомянуто здесь, не помогло. Я также заметил, что тестовое консольное приложение отлично работает под пользователем пула.

Проблема исчезла после очистки параметра "Включить 32-разрядные приложения" для пула приложений IIS.

После принятия принятого ответа (с указанием KeySpec) исключение изменилось на System.Security.Cryptography.CryptographicException: Invalid provider type specified.. Я разрешил это исключение, предоставив своему веб-приложению доступ к закрытому ключу (IIS_IUSRS). Я обнаружил, что это также решит проблему с моим исходным сертификатом. Поэтому перед созданием и развертыванием новых сертификатов также проверьте разрешения закрытого ключа.

Для службы WCF.net 4.8 я получал эту ошибку, потому что я (также) не установил версию httpRuntime.

Без набора httpRuntime я получал ошибку всякий раз, когда присутствовала защищенная привязка tcp.net.

<system.web>
    <compilation targetFramework="4.8" />
    <httpRuntime targetFramework="4.8" />
    <!--<customErrors mode="Off" />-->
</system.web>

Я уже установил необходимые разрешения в mmc.exe -> добавить оснастку -> сертификаты -> личные -> все задачи -> управлять закрытыми ключами -> добавить [имя компьютера]\IIS_IUSRS (все мои пулы приложений - ApplicationPoolIdentity [по умолчанию ] - покрывается IIS_IUSRS)

У меня была очень странная проблема с импортированным PFX из OpenSSL в системе Linux и ADWS (веб-служба Active Directory).

При использовании графического пользовательского интерфейса импорта сертификата через оснастку MMC сертификат был успешно импортирован, и ADWS смогла его найти и загрузить.

При использовании этой команды с Powershell сертификат был успешно импортирован, но ADWS выдавал ошибку Event ID 1402.

Import-PfxCertificate -FilePath C:\Users\Administrator\Desktop\dc01.test.pfx `
   -CertStoreLocation 'Cert:\LocalMachine\My' -Password (ConvertTo-SecureString 'Password123!' -AsPlainText -Force)
Веб-службам Active Directory не удалось обработать сертификат сервера. Для использования соединений SSL/TLS требуется сертификат. Чтобы использовать соединения SSL/TLS, убедитесь, что на машине установлен действительный сертификат проверки подлинности сервера от доверенного центра сертификации (ЦС).

Включение отладки было причиной:

ADWSHostFactory: [01.04.2023, 21:55:59] [6] ProvisionCertificate: поймано исключение CryptographicException: System.Security.Cryptography.CryptographicException: указан недопустимый тип поставщика.

   в System.Security.Cryptography.Utils.CreateProvHandle(параметры CspParameters, логическое значение randomKeyContainer)
   в System.Security.Cryptography.Utils.GetKeyPairHelper(CspAlgorithmType keyType, параметры CspParameters, логические значения randomKeyContainer, Int32 dwKeySize, SafeProvHandle и safeProvHandle, SafeKeyHandle и safeKeyHandle)
   в System.Security.Cryptography.RSACryptoServiceProvider.GetKeyPair()
   в System.Security.Cryptography.RSACryptoServiceProvider..ctor(Int32 dwKeySize, параметры CspParameters, логическое значение useDefaultKeySize)
   в System.Security.Cryptography.X509Certificates.X509Certificate2.get_PrivateKey()
   в Microsoft.ActiveDirectory.WebServices.ADWSHostFactory.ProvisionCertificate(хост ServiceHost)

Я был в тупике и попробовал некоторые другие решения здесь, но ничего не сработало.

К счастью, я обнаружил это руководство в Component Space (https://www.componentspace.com/Forums/1578/SHA256-and-Converting-the-Cryptographic-Service-Provider-Type), в котором упоминается, что провайдер криптографии является проблемой, как и много других по этому вопросу.

Я не видел способа изменить это с помощью powershell, но вы можете сделать это с помощью certutil.

   certutil.exe -p 'Пароль123!' -csp "Microsoft Enhanced RSA and AES Cryptographic Provider" -importPFX C:\Users\Administrator\Desktop\dc01.test.pfx

Сертификат теперь работает так, как если бы я добавил его через графический интерфейс.

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

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

Получите сертификат и извлеките из него файл pfx.

используйте пароль 123456 ниже, чтобы найти быстрое решение.

переименуйте свой pfx в файл my.pfx, чтобы упростить его, и поместите его в "C:\Certi", убедитесь, что в системе уже установлен открытый SSL. откройте cmd в системе Windows и введите -> OpenSSL Сохраняйте спокойствие и просто запускайте их по одному -> копировать и вставлять. *Запись

- passin - это пароль вашего файла Pfx - passout - это новый пароль для преобразованного файла PFX.

1. pkcs12 -in "C:\Certi\my.pfx" -nokeys -out "C:\Certi\MYCERT.cer" -passin "pass:123456"

2. pkcs12 -in "C:\Certi\my.pfx" -nocerts –out “C:\Certi\MYCERT.pem" -passin "pass:123456" -passout "pass:123456"

3. rsa -inform PEM -in "C:\Certi\MYCERT.pem" -out "C:\Certi\MYCERT.rsa" -passin "pass:123456" -passout "pass:123456"

если вы столкнулись с проблемой в третьей команде, перейдите сюда https://decoder.link/converter
Щелкните PKC#12, чтобы загрузить PEM файл pfx и преобразовать его онлайн. загрузите zip-файл. он содержит 3 файла. просто скопируйте файл ".key", переименуйте его в my.key и вставьте в "C:\Certi"

4. rsa -in C:\Certi\my.key -out C:\Certi\domain-rsa.key

5. pkcs12 -export -in "C:\Certi\MYCERT.cer" -inkey "C:\Certi\domain-rsa.key" -out "C:\Certi\CONVERTED.pfx" -passin "pass:123456" -passout "pass:123456"


**Also, you can try below things if the issue still persists**
  • Имеется доступ к пулу приложений или пользователю IIS к папке "обязательно для выполнения"

Путь --- > C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys

  • Удалите старые ключи (
    уберите беспорядок) Путь --- > C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys

У меня также была эта проблема, я изменил '.jks' на '.pfx', не вводя пароль, как только я снова изменил тип хранилища ключей с паролем, он успешно работает.

Эта ошибка исчезла после того, как я удалил сертификат из магазина и снова импортировал его из файла.pfx с помощью мастера импорта сертификатов (дважды щелкните файл.pfx) и дополнительной опции импорта.

После проверки опции импорта (тот же шаг, где вводится пароль):

"Отметьте этот ключ как экспортируемый. Это позволит вам сделать резервную копию или перенести ключи позже".

К закрытому ключу теперь можно было получить доступ из кода без каких-либо ошибок.

Я также явно выбираю "Личное" хранилище на предпоследнем шаге, но я не думаю, что это имеет значение.

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

Политики безопасности, вероятно, ограничивали использование CSP, полагающихся на устаревшие криптографические алгоритмы .

Обновление CSP до поставщика хранилища ключей программного обеспечения Microsoft на основе этих инструкций устранило проблемы.

Кажется, что в Windows 10, если я запускаю свою программу без административных прав (независимо от того, использую ли я свойство PrivateKey или метод расширения GetRSAPrivateKey()), я увижу это исключение (см. Заголовок этой ветки обсуждения для исключения). Если я запускаю свою программу с правами администратора и использую свойство PrivateKey, я также увижу это исключение. Только если я запускаю свою программу с правами администратора и использую метод расширения GetRSAPrivateKey(), я не увижу этого исключения.

Другие вопросы по тегам