Доброго времени суток, коллеги.
Для работы с КриптоПро CSP использую Sharpei.
Имеется клиент Web Service'а, отсылающий подписанные ЭЦП запросы на сервер. Клиент в ОС работает как сервис, а значит в нём не должно быть никакого взаимодействия с GUI от КриптоПро CSP.
1) Перед тем как создать ЭЦП необходимо получить доступ к сертификату.
2) Я получаю следующие данные:
- имя контейнера, в котором находится сертификат
- пароль к данному контейнеру
3) По полученным данным получаю доступ к сертификату и дальше как нужно работаю.
Код выглядит так:
Код:
CspParameters cspParameters = BuildCertificateCspParameters()
Gost3410CryptoServiceProvider provider = new Gost3410CryptoServiceProvider(cspParameters);
X509Certificate2 certificate2 = provider.ContainerCertificate;// достаем сертификат из контейнера
...
private CspParameters BuildCertificateCspParameters()
{
var cspParameters = new CspParameters();
cspParameters.KeyContainerName = _сontainerName; //имя используемого контейнера
cspParameters.ProviderType = 75;//номер используемого провайдера
cspParameters.Flags = CspProviderFlags.NoPrompt; //отключение GUI-форм КриптоПро CSP
cspParameters.KeyPassword = BuildCspParametersPassword();
return cspParameters;
}
...
private SecureString BuildCspParametersPassword()
{
var secure = new SecureString();
foreach (char charPass in _сontainerPass)
{
secure.AppendChar(charPass);
}
return secure;
}
Проблема в том, что данный код работает (по умолчанию) только если ключевой контейнер КриптоПро установлен для "пользователя" (StoreLocation.CurrentUser). Если контейнер установлен для компьютера (StoreLocation.LocalMachine), то код не работает и падает с ошибкой:
Цитата:System.Security.Cryptography.CryptographicException: Неправильный параметр набора ключей.
в CryptoPro.Sharpei.CPUtils.CreateProvHandle(CspParameters parameters, Boolean randomKeyContainer)
в CryptoPro.Sharpei.CPUtils.GetKeyPairHelper(CPCspAlgorithmType keyType, CspParameters parameters, Boolean randomKeyContainer, Int32 dwKeySize, SafeProvHandleCP& safeProvHandle, SafeKeyHandleCP& safeKeyHandle)
в CryptoPro.Sharpei.Gost3410CryptoServiceProvider.GetKeyPair()
...
Вопрос: можно ли где-то в настройках явно указать расположение контейнера (StoreLocation.LocalMachine или StoreLocation.CurrentUser). Ничего подходящего
для себя пока в CspParameters или в Gost3410CryptoServiceProvider не нашёл.
---
Для решения проблемы использую такой код.
Код:
X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadWrite);
509Certificate2Collection fcollection = (X509Certificate2Collection)store.Certificates;
...<произвожу поиск в fcollection>...
X509Certificate2 certificate = collection[i];
CspKeyContainerInfo info = ((ICspAsymmetricAlgorithm)certificate.PrivateKey).CspKeyContainerInfo;
var provider = new Gost3410CryptoServiceProvider();
Если нужный сертификат не найден, то повторяю поиск уже в StoreLocation.LocalMachine.
Проблемы:
- нужны данные о сертификате, с которым производится работа (то что его будет идентифицировать);
- раньше в коде я не замарачивался о том с каким сертификатом работаю, ибо контейнер КриптоПро CSP содержит всегда только 1 сертификат
PS:
Мне необходимо обязательно задавать перед началом работы с криптопровайдером:
CspProviderFlags.NoPrompt;для того, чтобы не появлялись GUI окна.
Я проверяю полученный пароль на валидность
Код: var dummyHash = new byte[32];
try
{
provider.SignHash(dummyHash); //если ошибка - пароль не верный
}
catch (Exception)
{
throw new Exception("текст");
}
И если он неверен, то отдаю соответствующую ошибку.
PSS:
1) Нашёл, что можно задать через CspParameters:
cspParameters.Flags = CspProviderFlags.UseMachineKeyStore;Но это не подходит ибо подавление GUI-окон не действует и в случае неправильно введенного пароля в представленном выше коде всплывет окно с предложением повторить ввод пароля. Т.е. по сути мне нужно:
Код:cspParameters.Flags = CspProviderFlags.UseMachineKeyStore;
и
cspParameters.Flags = CspProviderFlags.NoPrompt;
а это одновременно сейчас невозможно.
2) Нашёл ещё:
Gost3410CryptoServiceProvider.UseMachineKeyStore = true;но судя по описанию кода класса Gost3410CryptoServiceProvider получается:
Код: public static bool UseMachineKeyStore
{
get
{
return Gost3410CryptoServiceProvider.useMachineKeyStore_ == CspProviderFlags.UseMachineKeyStore;
}
set
{
Gost3410CryptoServiceProvider.useMachineKeyStore_ = value ? CspProviderFlags.UseMachineKeyStore : CspProviderFlags.NoFlags;
}
}
что теряет свою суть.
Прошу вашей помощи в решении возникшей проблемы.