Статус: Новичок
Группы: Участники
Зарегистрирован: 19.10.2018(UTC) Сообщений: 1 Откуда: Санкт-Петербург Сказал(а) «Спасибо»: 1 раз
|
Здравствуйте! На компьютер установлена КриптоПро CSP 4.0 КС2. Занимаюсь разработкой утилиты для экспорта сертификатов. До этого поддерживались только сертификаты с алгоритмом подписи ГОСТ Р 34.10-2001. Сейчас реализую поддержку сертификатов с алгоритмом подписи ГОСТ Р 34.10-2012. Есть следующий метод, который экспортирует сертификат и сохраняет в файл (WinCapi - класс, в который импортированы методы из библиотек crypt32.dll, advapi32.dll): Код:
static uint PROV_GOST_2001_DH = 75;
static uint PROV_GOST_2012_256 = 80;
static uint PROV_GOST_2012_512 = 81;
static uint CRYPT_SILENT = 0x00000040;
static int CRYPT_EXPORTABLE = 0x00000001;
static uint CALG_GR3411 = 32798;
static uint CALG_GR3411_2012_256 = 32801;
static uint CALG_GR3411_2012_512 = 32802;
static uint PP_KEYEXCHANGE_PIN = 32;
static uint AT_KEYEXCHANGE = 1;
static uint CALG_G28147 = 26142;
static uint CALG_PRO_EXPORT = 26143;
static int KP_ALGID = 7;
static uint KP_CERTIFICATE = 26
static int PRIVATEKEYBLOB = 0x7;
public static bool exportKey(String containerName, String filePath, String transitPass, String containerPass, String certFilePath, ContainerTypeEnum type)
{
IntPtr hProvResponder = IntPtr.Zero;
IntPtr hResponderKey = IntPtr.Zero;
IntPtr hash = IntPtr.Zero;
IntPtr sessionKey = IntPtr.Zero;
int keyBufLen = 0;
uint calg;
bool result;
switch (type)
{
case ContainerTypeEnum.GOST_2001:
result = WinCapi.CryptAcquireContext(ref hProvResponder, containerName, null, PROV_GOST_2001_DH, CRYPT_SILENT);
calg = CALG_GR3411;
break;
case ContainerTypeEnum.GOST_2012_256:
result = WinCapi.CryptAcquireContext(ref hProvResponder, containerName, null, PROV_GOST_2012_256, CRYPT_SILENT);
calg = CALG_GR3411_2012_256;
break;
case ContainerTypeEnum.GOST_2012_512:
result = WinCapi.CryptAcquireContext(ref hProvResponder, containerName, null, PROV_GOST_2012_512, CRYPT_SILENT);
calg = CALG_GR3411_2012_512;
break;
default:
result = false;
calg = 0;
break;
}
if (!result)
{
HandleError("не удалось найти или подсоединиться к контейнеру");
return false;
}
if (!WinCapi.CryptSetProvParam(hProvResponder, PP_KEYEXCHANGE_PIN, Utilities.StrToByteArray(containerPass), 0))
{
WinCapi.CryptReleaseContext(hProvResponder, 0);
return false;
}
if (!WinCapi.CryptGetUserKey(hProvResponder, AT_KEYEXCHANGE, ref hResponderKey))
{
HandleError("Error during CryptGetUserKey public key.");
WinCapi.CryptReleaseContext(hProvResponder, 0);
return false;
}
if (!WinCapi.CryptCreateHash(hProvResponder, calg, IntPtr.Zero, 0, ref hash))
{
WinCapi.CryptReleaseContext(hProvResponder, 0);
WinCapi.CryptDestroyKey(hResponderKey);
HandleError("hach not created");
return false;
}
if (!WinCapi.CryptHashData(hash, Utilities.StrToByteArray(transitPass), transitPass.Length, 0))
{
HandleError("data not hashed");
WinCapi.CryptDestroyHash(hash);
WinCapi.CryptReleaseContext(hProvResponder, 0);
WinCapi.CryptDestroyKey(hResponderKey);
return false;
}
if (!WinCapi.CryptDeriveKey(hProvResponder, CALG_G28147, hash, CRYPT_EXPORTABLE, ref sessionKey))
{
HandleError("derive key fail");
WinCapi.CryptDestroyHash(hash);
WinCapi.CryptReleaseContext(hProvResponder, 0);
WinCapi.CryptDestroyKey(hResponderKey);
return false;
}
uint algid_export = CALG_PRO_EXPORT;
if (WinCapi.CryptSetKeyParam(sessionKey, KP_ALGID, BitConverter.GetBytes(algid_export), 0))
{
//Console.WriteLine("ключ экспорта настроен");
}
else
{
HandleError("ошибка при установке ключа экспорта");
WinCapi.CryptDestroyKey(sessionKey);
WinCapi.CryptDestroyHash(hash);
WinCapi.CryptReleaseContext(hProvResponder, 0);
WinCapi.CryptDestroyKey(hResponderKey);
return false;
}
if (!WinCapi.CryptExportKey(hResponderKey, sessionKey, PRIVATEKEYBLOB, 0, null, ref keyBufLen))
{
HandleError("ошибка при получении размера закрытого ключа");
WinCapi.CryptDestroyKey(sessionKey);
WinCapi.CryptDestroyHash(hash);
WinCapi.CryptReleaseContext(hProvResponder, 0);
WinCapi.CryptDestroyKey(hResponderKey);
return false;
}
Byte[] keyBuff = new Byte[keyBufLen];
if (WinCapi.CryptExportKey(hResponderKey, sessionKey, PRIVATEKEYBLOB, 0, keyBuff, ref keyBufLen))
{
//Console.WriteLine("ключ экспортирован");
}
else
{
HandleError("ошибка при экспорте закрытого ключа 1");
WinCapi.CryptDestroyKey(sessionKey);
WinCapi.CryptDestroyHash(hash);
WinCapi.CryptReleaseContext(hProvResponder, 0);
WinCapi.CryptDestroyKey(hResponderKey);
return false;
}
bool res = true;
//экспорт сертификата
uint certLen = 0;
Byte[] certData = null;
if (WinCapi.CryptGetKeyParam(hResponderKey, KP_CERTIFICATE, null, ref certLen, 0))
{
certData = new Byte[certLen];
if (WinCapi.CryptGetKeyParam(hResponderKey, KP_CERTIFICATE, certData, ref certLen, 0))
{
File.WriteAllBytes(certFilePath, certData);
}
}
else
{
HandleError("не удалось получить сертификат, привязанный к контейнеру");
res = false;
}
File.WriteAllBytes(filePath, keyBuff);
//temp
return res;
}
Проблема возникает в вызове метода CryptExportKey, возвращается ошибка 2146893813 "Ключ не может быть использован в указанном состоянии". Поиск по форуму показал, что это связано с разрешением на экспорт ключа. Разрешение проверил в CSP->Сервис->Протестировать, результат ниже: Проверка завершена успешно ошибок не обнаружено Контейнер закрытого ключа пользователя имя c6a48e71-12d3-460d-ad2d-733d614b32b9 уникальное имя REGISTRY\\c6a48e71-12d3-460d-ad2d-733d614b32b9 FQCN \\.\REGISTRY\c6a48e71-12d3-460d-ad2d-733d614b32b9 проверка целостности контейнера успешно Ключ обмена доступен длина ключа 512 бит экспорт открытого ключа успешно вычисление открытого ключа успешно импорт открытого ключа успешно подпись успешно проверка успешно создание ключа обмена успешно экспорт ключа разрешен алгоритм ГОСТ Р 34.10-2012 DH 256 бит ГОСТ Р 34.10-2001, параметры обмена по умолчанию ГОСТ Р 34.11-2012 256 бит ГОСТ 28147-89, параметры шифрования ТК26 Z сертификат в контейнере отсутствует Ключ подписи отсутствует загрузка ключей успешно Версия контейнера 2 Как можно решить эту проблему? Допускаю, что для поддержки сертификатов с ГОСТ Р 34.10-2012 требуется еще как то изменить код, но информации об этом не нашел. Может ли эта ошибка говорить не только о запрете на экспорт?
|