Я проводил некоторые тесты, когда натолкнулся на это очень странное поведение… которого я не до конца понимаю.
Сначала я создал самозаверяющий сертификат с помощью Powershell:
# Creates a certificate and adds it to the certificate store (private key included)
$certInfo = New-SelfSignedCertificate -NotBefore (Get-Date) -NotAfter (Get-Date).AddYears(300) -Subject "MyTestCert" -DnsName "localhost" -KeyAlgorithm "RSA" -KeyLength 2048 -HashAlgorithm "SHA256" -CertStoreLocation "Cert:\LocalMachine\My" -FriendlyName "MyTestCert"
Write-Host "Created cert: $($certInfo.Subject) - $($certInfo.Thumbprint)"
# Exports the certificate as pfx (private key included)
$PFXPass = ConvertTo-SecureString -String "123456" -Force -AsPlainText
Export-PfxCertificate -Cert "cert:\LocalMachine\My\$($certInfo.Thumbprint)" -Password $PFXPass -FilePath "C:\Temp\$($certInfo.Subject.SubString(3)).pfx"
При этом успешно создается сертификат с темой «MyTestCert» и сертификат имеет закрытый ключ.
![Windows key store](https://i.stack.imgur.com/2XSB5.png)
Глядя на разрешения (Все задачи> Управление личными ключами…), вы видите, что ключ доступен для администраторов, но не для «обычных» пользователей.
![Manage private keys](https://i.stack.imgur.com/zJpZR.png)
Затем я выполнил свой код C # (ядро .NET 2.2) (VS отладка, работает без прав администратора), который читает сертификат из хранилища и пытается использовать закрытый ключ сертификатов:
internal class Program
{
private static X509Certificate2 GetCertFromFile()
{
const String certFileName = @"C:\Temp\MyTestCert.pfx";
var cert = new X509Certificate2( certFileName, "123456", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet );
return cert;
}
private static X509Certificate2 GetCertFromStore()
{
using ( var store = new X509Store( StoreName.My, StoreLocation.LocalMachine ) )
{
store.Open( OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly );
var matchingCerts = store.Certificates.Find( X509FindType.FindBySubjectName, "MyTestCert", false );
return matchingCerts[0];
}
}
private static void Main( String[] args )
{
var certificate = GetCertFromStore();
// Does throw exception "Keyset does not exist"
try
{
var rsa = certificate.GetRSAPrivateKey();
}
catch ( CryptographicException ex )
{
Console.WriteLine( ex );
}
certificate = GetCertFromFile();
// This will work
var rsa1 = certificate.GetRSAPrivateKey();
Console.ReadLine();
}
}
Как и ожидалось, сертификат, загруженный из хранилища (GetCertFromFile
), не содержит закрытого ключа.
(Сертификат содержит закрытый ключ при исполнении от имени администратора.)
Сертификат, загруженный из файла PFX (GetCertFromFile
), содержит закрытый ключ.
Теперь начинается странная часть.
Когда я запускаю приложение во второй раз, сертификат, загруженный из хранилища (GetCertFromFile
), содержит закрытый ключ.
Почему хранилище ключей дает мне доступ к закрытому ключу сертификата ПОСЛЕ того, как я прочитал файл PFX?