using System.Collections;
using System.Reflection;
using System.Resources;
using System.Security.Cryptography.X509Certificates;
using System.Text;
namespace CertificateChecker;
///
/// Основной класс для проверки сертификатов
///
public class CertificateChecker
{
///
/// Загружает сертификаты из Resources.resx
///
public List LoadCertificatesFromResources()
{
var certificates = new List();
var assembly = Assembly.GetExecutingAssembly();
Console.WriteLine(" 📂 Поиск сертификатов в ресурсах...");
Console.WriteLine($" Сборка: {assembly.GetName().Name}");
try
{
// Получаем ВСЕ ресурсы из сборки
var resourceNames = assembly.GetManifestResourceNames();
Console.WriteLine($" Найдено ресурсов: {resourceNames.Length}");
if (resourceNames.Length == 0)
{
Console.WriteLine(" ⚠️ Ресурсы не найдены. Проверьте файл Resources.resx");
return certificates;
}
// Ищем ресурсы, которые содержат "Resources" в названии
var resourcesFile = resourceNames.FirstOrDefault(r => r.Contains("Resources"));
if (string.IsNullOrEmpty(resourcesFile))
{
Console.WriteLine(" ⚠️ Файл Resources.resx не найден");
Console.WriteLine($" Доступные ресурсы: {string.Join(", ", resourceNames)}");
return certificates;
}
Console.WriteLine($" Найден файл ресурсов: {resourcesFile}");
// Создаем ResourceManager для найденного файла
var resourceManagerName = Path.GetFileNameWithoutExtension(resourcesFile);
Console.WriteLine($" Имя ResourceManager: {resourceManagerName}");
var resourceManager = new ResourceManager(resourceManagerName, assembly);
// Получаем все ресурсы
var resourceSet = resourceManager.GetResourceSet(System.Globalization.CultureInfo.InvariantCulture, true, true);
if (resourceSet == null)
{
Console.WriteLine(" ❌ Не удалось загрузить ResourceSet");
return certificates;
}
// Собираем все ключи ресурсов
var keys = new List();
foreach (DictionaryEntry entry in resourceSet)
{
keys.Add(entry.Key.ToString());
}
Console.WriteLine($" Найдено ключей в ресурсах: {keys.Count}");
Console.WriteLine($" Ключи: {string.Join(", ", keys)}");
// Фильтруем ключи, которые содержат "cert", "ca", "root", "sub"
var certKeys = keys
.Where(key => key.ToLower().Contains("cert") ||
key.ToLower().Contains("ca") ||
key.ToLower().Contains("root") ||
key.ToLower().Contains("sub"))
.ToList();
if (!certKeys.Any())
{
Console.WriteLine(" ⚠️ Сертификаты в ресурсах не найдены");
Console.WriteLine($" Ищите ключи содержащие: cert, ca, root, sub");
return certificates;
}
Console.WriteLine($"\n Найдено сертификатов: {certKeys.Count}");
foreach (var key in certKeys)
{
try
{
Console.WriteLine($"\n 📄 Загрузка: {key}");
// Получаем значение ресурса
var value = resourceManager.GetObject(key);
if (value == null)
{
Console.WriteLine($" ❌ Ресурс {key} пустой");
continue;
}
// Проверяем тип ресурса
if (value is byte[] bytes)
{
if (bytes.Length == 0)
{
Console.WriteLine($" ❌ Ресурс {key} пустой (0 байт)");
continue;
}
Console.WriteLine($" Размер: {bytes.Length} байт");
try
{
// Пробуем загрузить как сертификат
var certificate = new X509Certificate2(bytes);
// Устанавливаем понятное имя
if (string.IsNullOrEmpty(certificate.FriendlyName))
{
certificate.FriendlyName = key.Replace("_", " ").Trim();
}
certificates.Add(certificate);
Console.WriteLine($" ✅ Загружен сертификат: {certificate.FriendlyName}");
Console.WriteLine($" Субъект: {certificate.Subject}");
Console.WriteLine($" Отпечаток: {certificate.Thumbprint}");
Console.WriteLine($" Действителен до: {certificate.NotAfter:dd.MM.yyyy}");
Console.WriteLine($" Закрытый ключ: {(certificate.HasPrivateKey ? "✅ Есть" : "❌ Нет")}");
}
catch (Exception ex)
{
Console.WriteLine($" ⚠️ Не удалось загрузить {key} как сертификат: {ex.Message}");
Console.WriteLine($" Возможно это не сертификат или требуется пароль");
// Пробуем с паролем для PFX
if (key.ToLower().Contains("pfx") || key.ToLower().Contains("p12") || key.ToLower().Contains("gost"))
{
Console.Write(" 🔑 Введите пароль для {0}: ", key);
var password = Console.ReadLine();
if (!string.IsNullOrEmpty(password))
{
try
{
var certificate = new X509Certificate2(bytes, password);
certificate.FriendlyName = key.Replace("_", " ").Trim();
certificates.Add(certificate);
Console.WriteLine($" ✅ Загружен с паролем: {certificate.FriendlyName}");
}
catch (Exception ex2)
{
Console.WriteLine($" ❌ Ошибка загрузки с паролем: {ex2.Message}");
}
}
}
}
}
else
{
Console.WriteLine($" ⚠️ Ресурс {key} имеет тип {value.GetType().Name}, ожидался byte[]");
}
}
catch (Exception ex)
{
Console.WriteLine($" ❌ Ошибка обработки {key}: {ex.Message}");
}
}
}
catch (Exception ex)
{
Console.WriteLine($" ❌ Общая ошибка: {ex.Message}");
Console.WriteLine($" {ex.StackTrace}");
}
Console.WriteLine($"\n ИТОГО загружено сертификатов: {certificates.Count}");
return certificates;
}
///
/// Проверяет, установлен ли сертификат на ПК
///
public async Task CheckCertificateInstalledAsync(X509Certificate2 certificate)
{
var result = new CertificateCheckResult
{
FriendlyName = certificate.FriendlyName,
Subject = certificate.Subject,
Issuer = certificate.Issuer,
SerialNumber = certificate.SerialNumber,
NotBefore = certificate.NotBefore,
NotAfter = certificate.NotAfter,
Thumbprint = certificate.Thumbprint,
IsInstalled = false,
FoundInStores = new List(),
HasPrivateKey = certificate.HasPrivateKey
};
// Проверяем в разных хранилищах
var stores = new[]
{
(StoreName.My, StoreLocation.CurrentUser, "Личные (CurrentUser)"),
(StoreName.My, StoreLocation.LocalMachine, "Личные (LocalMachine)"),
(StoreName.Root, StoreLocation.CurrentUser, "Доверенные корневые (CurrentUser)"),
(StoreName.Root, StoreLocation.LocalMachine, "Доверенные корневые (LocalMachine)"),
(StoreName.TrustedPeople, StoreLocation.CurrentUser, "Доверенные лица (CurrentUser)"),
(StoreName.TrustedPeople, StoreLocation.LocalMachine, "Доверенные лица (LocalMachine)"),
(StoreName.CertificateAuthority, StoreLocation.CurrentUser, "Промежуточные (CurrentUser)"),
(StoreName.CertificateAuthority, StoreLocation.LocalMachine, "Промежуточные (LocalMachine)"),
(StoreName.AddressBook, StoreLocation.CurrentUser, "Адресная книга (CurrentUser)"),
(StoreName.AddressBook, StoreLocation.LocalMachine, "Адресная книга (LocalMachine)")
};
foreach (var (storeName, storeLocation, displayName) in stores)
{
try
{
using var store = new X509Store(storeName, storeLocation);
store.Open(OpenFlags.ReadOnly);
// Ищем по отпечатку
var foundCerts = store.Certificates.Find(X509FindType.FindByThumbprint, certificate.Thumbprint, false);
if (foundCerts.Count > 0)
{
result.IsInstalled = true;
result.StoreName = storeName;
result.StoreLocation = storeLocation;
result.FoundCertificate = foundCerts[0];
result.FoundInStores.Add(displayName);
}
}
catch
{
// Некоторые хранилища могут быть недоступны
}
}
// Проверка цепочки сертификатов
result.ChainValidationResult = await ValidateCertificateChainAsync(certificate);
// Проверка срока действия
result.IsValid = DateTime.Now >= certificate.NotBefore &&
DateTime.Now <= certificate.NotAfter;
return result;
}
///
/// Проверка цепочки сертификатов
///
private async Task ValidateCertificateChainAsync(X509Certificate2 certificate)
{
var result = new ChainValidationResult();
try
{
using var chain = new X509Chain();
chain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot;
var isValid = chain.Build(certificate);
result.IsValid = isValid;
result.Status = chain.ChainStatus
.Select(s => new ChainStatusInfo
{
Status = s.Status,
StatusInformation = s.StatusInformation
})
.ToList();
}
catch (Exception ex)
{
result.ErrorMessage = ex.Message;
}
return result;
}
///
/// Проверяет сертификат по отпечатку
///
public bool IsCertificateInstalled(string thumbprint)
{
var stores = new[]
{
(StoreName.My, StoreLocation.CurrentUser),
(StoreName.My, StoreLocation.LocalMachine),
(StoreName.Root, StoreLocation.CurrentUser),
(StoreName.Root, StoreLocation.LocalMachine)
};
foreach (var (storeName, storeLocation) in stores)
{
try
{
using var store = new X509Store(storeName, storeLocation);
store.Open(OpenFlags.ReadOnly);
var certificates = store.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false);
if (certificates.Count > 0)
return true;
}
catch
{
// Пропускаем недоступные хранилища
}
}
return false;
}
///
/// Устанавливает сертификат в указанное хранилище
///
public async Task InstallCertificateAsync(X509Certificate2 certificate, StoreName storeName, StoreLocation storeLocation, string friendlyName = "")
{
try
{
Console.WriteLine($"\n 📥 Установка сертификата {friendlyName} в {storeLocation}\\{storeName}...");
using var store = new X509Store(storeName, storeLocation);
store.Open(OpenFlags.ReadWrite);
// Проверяем, не установлен ли уже
var existing = store.Certificates.Find(X509FindType.FindByThumbprint, certificate.Thumbprint, false);
if (existing.Count > 0)
{
Console.WriteLine($" ⚠️ Сертификат уже установлен в {storeLocation}\\{storeName}");
return true;
}
// Устанавливаем понятное имя
if (!string.IsNullOrEmpty(friendlyName))
{
certificate.FriendlyName = friendlyName;
}
store.Add(certificate);
store.Close();
Console.WriteLine($" ✅ Сертификат успешно установлен в {storeLocation}\\{storeName}");
return true;
}
catch (Exception ex)
{
Console.WriteLine($" ❌ Ошибка установки: {ex.Message}");
return false;
}
}
///
/// Устанавливает сертификат с автоматическим выбором хранилища
///
public async Task InstallCertificateWithAutoStoreAsync(X509Certificate2 certificate)
{
var result = new InstallResult
{
Certificate = certificate,
Success = false,
Messages = new List()
};
// Определяем куда устанавливать в зависимости от типа сертификата
var subject = certificate.Subject.ToLower();
var isRoot = subject.Contains("root") || subject.Contains("ca") && !subject.Contains("sub");
var isCA = subject.Contains("ca");
var isPersonal = subject.Contains("client") || subject.Contains("user") || subject.Contains("person");
List<(StoreName store, StoreLocation location, string description)> storesToInstall;
if (isRoot)
{
// Корневой сертификат
storesToInstall = new List<(StoreName, StoreLocation, string)>
{
(StoreName.Root, StoreLocation.LocalMachine, "Доверенные корневые (LocalMachine)"),
(StoreName.Root, StoreLocation.CurrentUser, "Доверенные корневые (CurrentUser)")
};
result.InstallType = "Корневой сертификат";
}
else if (isCA && !isRoot)
{
// Промежуточный сертификат
storesToInstall = new List<(StoreName, StoreLocation, string)>
{
(StoreName.CertificateAuthority, StoreLocation.LocalMachine, "Промежуточные (LocalMachine)"),
(StoreName.CertificateAuthority, StoreLocation.CurrentUser, "Промежуточные (CurrentUser)")
};
result.InstallType = "Промежуточный сертификат";
}
else if (isPersonal)
{
// Личный сертификат
storesToInstall = new List<(StoreName, StoreLocation, string)>
{
(StoreName.My, StoreLocation.CurrentUser, "Личные (CurrentUser)"),
(StoreName.My, StoreLocation.LocalMachine, "Личные (LocalMachine)")
};
result.InstallType = "Личный сертификат";
}
else
{
// Неопределенный тип - устанавливаем в личные
storesToInstall = new List<(StoreName, StoreLocation, string)>
{
(StoreName.My, StoreLocation.CurrentUser, "Личные (CurrentUser)")
};
result.InstallType = "Неопределенный тип (личный)";
}
Console.WriteLine($"\n 📌 Тип сертификата: {result.InstallType}");
Console.WriteLine($" 📌 Субъект: {certificate.Subject}");
// Устанавливаем в каждое хранилище
foreach (var (store, location, description) in storesToInstall)
{
try
{
var success = await InstallCertificateAsync(certificate, store, location, certificate.FriendlyName);
if (success)
{
result.Success = true;
result.InstalledStores.Add($"{location}\\{store}");
result.Messages.Add($"✅ Установлен в {description}");
}
else
{
result.Messages.Add($"❌ Не удалось установить в {description}");
}
}
catch (Exception ex)
{
result.Messages.Add($"❌ Ошибка при установке в {description}: {ex.Message}");
}
}
// Если не удалось установить никуда, пробуем в CurrentUser
if (!result.Success)
{
Console.WriteLine($" ⚠️ Пробуем установить в CurrentUser...");
try
{
var success = await InstallCertificateAsync(certificate, StoreName.My, StoreLocation.CurrentUser, certificate.FriendlyName);
if (success)
{
result.Success = true;
result.InstalledStores.Add($"CurrentUser\\My");
result.Messages.Add($"✅ Установлен в Личные (CurrentUser)");
}
}
catch (Exception ex)
{
result.Messages.Add($"❌ Ошибка при установке в CurrentUser: {ex.Message}");
}
}
return result;
}
///
/// Удаляет сертификат из указанного хранилища
///
public async Task DeleteCertificateAsync(string thumbprint, StoreName storeName, StoreLocation storeLocation)
{
try
{
Console.WriteLine($"\n 🗑️ Удаление сертификата из {storeLocation}\\{storeName}...");
using var store = new X509Store(storeName, storeLocation);
store.Open(OpenFlags.ReadWrite);
var certificates = store.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false);
if (certificates.Count == 0)
{
Console.WriteLine($" ⚠️ Сертификат не найден в {storeLocation}\\{storeName}");
return false;
}
store.Remove(certificates[0]);
store.Close();
Console.WriteLine($" ✅ Сертификат удален из {storeLocation}\\{storeName}");
return true;
}
catch (Exception ex)
{
Console.WriteLine($" ❌ Ошибка удаления: {ex.Message}");
return false;
}
}
}
///
/// Результат проверки сертификата
///
public class CertificateCheckResult
{
public string FriendlyName { get; set; } = string.Empty;
public string Subject { get; set; } = string.Empty;
public string Issuer { get; set; } = string.Empty;
public string SerialNumber { get; set; } = string.Empty;
public DateTime NotBefore { get; set; }
public DateTime NotAfter { get; set; }
public string Thumbprint { get; set; } = string.Empty;
public bool IsInstalled { get; set; }
public bool IsValid { get; set; }
public bool HasPrivateKey { get; set; }
public StoreName StoreName { get; set; }
public StoreLocation StoreLocation { get; set; }
public X509Certificate2? FoundCertificate { get; set; }
public List FoundInStores { get; set; } = new();
public ChainValidationResult ChainValidationResult { get; set; } = new();
}
///
/// Результат установки сертификата
///
public class InstallResult
{
public X509Certificate2 Certificate { get; set; } = null!;
public bool Success { get; set; }
public string InstallType { get; set; } = string.Empty;
public List InstalledStores { get; set; } = new();
public List Messages { get; set; } = new();
}
///
/// Результат проверки цепочки сертификатов
///
public class ChainValidationResult
{
public bool IsValid { get; set; }
public string? ErrorMessage { get; set; }
public List Status { get; set; } = new();
}
///
/// Информация о статусе цепочки
///
public class ChainStatusInfo
{
public X509ChainStatusFlags Status { get; set; }
public string? StatusInformation { get; set; }
}