Как получить сертификат цифровой подписи в ридере?
Я работаю над приложением, которое работает с цифровой подписью (аутентификация и подписание документов) в проекте WPF. Для требований я должен использовать сертификат, который находится в картридер, для этого я использую код, взятый отсюда
Код, который я использую для получения сертификата, следующий:
private X509Certificate2 GetCertificate()
{
X509Store x509Store = null;
try
{
x509Store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
x509Store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
List<string> containers = GetContainerKey();
string pubKeyXml = null;
foreach (string container in containers)
{
CspParameters cspParameters = new CspParameters((int)NativeMethods.PROV_RSA_FULL, _providerName, container);
cspParameters.Flags = CspProviderFlags.UseExistingKey;
pubKeyXml = null;
using (RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider(cspParameters))
pubKeyXml = rsaProvider.ToXmlString(false);
foreach (X509Certificate2 cert in x509Store.Certificates)
{
if ((cert.PublicKey.Key.ToXmlString(false) == pubKeyXml) && cert.HasPrivateKey)
{
return cert;
}
}
}
}
catch (Exception e)
{
return null;
}
return null;
}
private static List<string> GetContainerKey()
{
List<string> containers = new List<string>();
IntPtr hProv = IntPtr.Zero;
try
{
if (!NativeMethods.CryptAcquireContext(ref hProv, null, _providerName, NativeMethods.PROV_RSA_FULL, NativeMethods.CRYPT_VERIFYCONTEXT))
throw new Win32Exception(Marshal.GetLastWin32Error());
uint pcbData = 0;
uint dwFlags = NativeMethods.CRYPT_FIRST;
if (!NativeMethods.CryptGetProvParam(hProv, NativeMethods.PP_ENUMCONTAINERS, null, ref pcbData, dwFlags))
throw new Win32Exception(Marshal.GetLastWin32Error());
StringBuilder sb = new StringBuilder((int)pcbData + 1);
while (NativeMethods.CryptGetProvParam(hProv, NativeMethods.PP_ENUMCONTAINERS, sb, ref pcbData, dwFlags))
{
containers.Add(sb.ToString());
dwFlags = NativeMethods.CRYPT_NEXT;
}
int err = Marshal.GetLastWin32Error();
if (err != NativeMethods.ERROR_NO_MORE_ITEMS)
{
try
{
if (containers.Count > 0)
throw new Win32Exception(err);
}
catch
{
containers = null;
}
}
if (hProv != IntPtr.Zero)
{
if (!NativeMethods.CryptReleaseContext(hProv, 0))
throw new Win32Exception(Marshal.GetLastWin32Error());
hProv = IntPtr.Zero;
}
}
catch
{
if (hProv != IntPtr.Zero)
{
if (!NativeMethods.CryptReleaseContext(hProv, 0))
throw new Win32Exception(Marshal.GetLastWin32Error());
hProv = IntPtr.Zero;
}
throw;
}
return containers;
}
private static class NativeMethods
{
public const uint PROV_RSA_FULL = 0x00000001;
public const uint CRYPT_VERIFYCONTEXT = 0xF0000000;
public const uint CRYPT_FIRST = 0x00000001;
public const uint CRYPT_NEXT = 0x00000002;
public const uint ERROR_NO_MORE_ITEMS = 0x00000103;
public const uint PP_ENUMCONTAINERS = 0x00000002;
[DllImport("advapi32.dll", BestFitMapping = false, ThrowOnUnmappableChar = true, SetLastError = true)]
public static extern bool CryptAcquireContext(
ref IntPtr phProv,
[MarshalAs(UnmanagedType.LPStr)] string pszContainer,
[MarshalAs(UnmanagedType.LPStr)] string pszProvider,
uint dwProvType,
uint dwFlags);
[DllImport("advapi32.dll", BestFitMapping = false, ThrowOnUnmappableChar = true, SetLastError = true)]
public static extern bool CryptGetProvParam(
IntPtr hProv,
uint dwParam,
[MarshalAs(UnmanagedType.LPStr)] StringBuilder pbData,
ref uint pdwDataLen,
uint dwFlags);
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool CryptReleaseContext(
IntPtr hProv,
uint dwFlags);
}
По сути, он получает открытый ключ и затем ищет в сертификатах, хранящихся в хранилище, открытый ключ, который соответствует. Я знаю, что он не работает для всех типов сертификатов (как сказано в примечаниях), но он работает для сертификатов с SHA256. Также мне нужно это для работы с сертификатами с SHA1. Я изменил параметры для csp, но я не могу получить открытый ключ для обоих типов форматов.
Кто-нибудь знает, как я могу получить сертификат цифровой подписи, которая находится в считывателе (для SHA1 и SHA256)?
Спасибо!