Ключевое слово в защите информации
КЛЮЧЕВОЕ СЛОВО
в защите информации
Получить ГОСТ TLS-сертификат для домена (SSL-сертификат)
Добро пожаловать, Гость! Чтобы использовать все возможности Вход или Регистрация.

Уведомление

Icon
Error

2 Страницы12>
Опции
К последнему сообщению К первому непрочитанному
Offline ahtoh  
#1 Оставлено : 16 января 2013 г. 14:59:29(UTC)
ahtoh

Статус: Участник

Группы: Участники
Зарегистрирован: 23.09.2011(UTC)
Сообщений: 17

Ubuntu 12.04

Сначало я получаю список всех контейнеров у которых есть закрытый ключ и есть сертификат ему соответсвующий, затем я сохраняю сертификат в виде байтового массива
Код:

HCRYPTPROV enumerationProvider = 0;
CryptAcquireContext(&enumerationProvider, 0, 0, PROV_GOST_2001_DH, CRYPT_VERIFYCONTEXT);
DWORD containerNameSize = 1024;
String containerNameLocal;
containerNameLocal.resize(containerNameSize);
if (CryptGetProvParam(enumerationProvider, PP_ENUMCONTAINERS, (BYTE*)containerNameLocal.data(), &containerNameSize, CRYPT_FIRST))
{
	WString alias;
	KeyInfo info;
	do
	{
		containerNameLocal.resize(containerNameSize);
		HCRYPTPROV containerProvider = 0;
		if(!CryptAcquireContextA(&containerProvider, containerNameLocal.c_str(), 0, PROV_GOST_2001_DH, 0))
		{
			continue;
		}
		HCRYPTKEY key = 0;
		if (!CryptGetUserKey(containerProvider, AT_SIGNATURE, &key))
		{
			CryptReleaseContext(containerProvider, 0);
			continue;
		}
		DWORD certificateSize = 0;
		if (!CryptGetKeyParam(key, KP_CERTIFICATE, 0, &certificateSize, 0))
		{
			CryptDestroyKey(key);
			CryptReleaseContext(containerProvider, 0);
			continue;
		}
		KeyInfo info;
		info.alias = getName(containerProvider, PP_CONTAINER);
		ByteArray certificate(certificateSize);
		poco_assert(CryptGetKeyParam(key, KP_CERTIFICATE, (BYTE*)certificate.data(), &certificateSize, 0));
		certificate.resize(certificateSize);
		info.certificate = certificate;
		CryptDestroyKey(key);
		CryptReleaseContext(containerProvider, 0);

		containerNameSize = 1024;
		containerNameLocal.resize(containerNameSize);
	} while(CryptGetProvParam(enumerationProvider, PP_ENUMCONTAINERS, (BYTE*)containerNameLocal.data(), &containerNameSize, CRYPT_NEXT));
}
CryptReleaseContext(enumerationProvider, 0);


После этого где то в другом месте происходит попытка получить контекс провайдера для закрытого ключа по его сертификату
Код:

_provider = 0;
_keySpec = AT_SIGNATURE;
_isNeedCleenup = TRUE;
PCERT_CONTEXT _certificate = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, (BYTE*)certificate.data(), (DWORD)certificate.size());
CryptAcquireCertificatePrivateKey(_certificate, CRYPT_SILENT, 0, &_provider, &_keySpec, &_isNeedCleenup);


CryptAcquireCertificatePrivateKey возвращает 0, GetLastError возвращает 0x80090020

Я знаю, что для Windows этот код работает только если установить личный сертификат из контейнера, но даже без установленного сертификата на Windows код ошибки возвращался более осмысленный.

Скажите пожалуйста где я не прав и/или что мне нужно сделать что бы это заработало.

Отредактировано пользователем 16 января 2013 г. 15:00:29(UTC)  | Причина: Не указана

Offline Максим Коллегин  
#2 Оставлено : 16 января 2013 г. 15:43:00(UTC)
Максим Коллегин

Статус: Сотрудник

Группы: Администраторы
Зарегистрирован: 12.12.2007(UTC)
Сообщений: 6,377
Мужчина
Откуда: КРИПТО-ПРО

Сказал «Спасибо»: 32 раз
Поблагодарили: 706 раз в 614 постах
Открывать криптопровайдер по сертификату без связи с закрытым ключом - плохая идея. На Windows работает из-за магических key identifier - на Linux мы это не реализовывали.
Знания в базе знаний, поддержка в техподдержке
Offline ahtoh  
#3 Оставлено : 16 января 2013 г. 16:19:34(UTC)
ahtoh

Статус: Участник

Группы: Участники
Зарегистрирован: 23.09.2011(UTC)
Сообщений: 17

На Windows в CAPI есть метод CryptFindCertificateKeyProvInfo, на Linux я его не нашел, подскажите пожалуйста как мне его реализовать.
Offline Максим Коллегин  
#4 Оставлено : 16 января 2013 г. 16:34:30(UTC)
Максим Коллегин

Статус: Сотрудник

Группы: Администраторы
Зарегистрирован: 12.12.2007(UTC)
Сообщений: 6,377
Мужчина
Откуда: КРИПТО-ПРО

Сказал «Спасибо»: 32 раз
Поблагодарили: 706 раз в 614 постах
Перечислить криптопровайдеры, в каждом криптопровайдере перечислить контейнеры и сравнить открытые ключи.
Знания в базе знаний, поддержка в техподдержке
Offline miser  
#5 Оставлено : 25 марта 2013 г. 16:04:01(UTC)
miser

Статус: Активный участник

Группы: Участники
Зарегистрирован: 14.03.2011(UTC)
Сообщений: 152
Мужчина
Откуда: Санкт-Петербург

Сказал «Спасибо»: 1 раз
Поблагодарили: 7 раз в 5 постах
Продолжу тему.
Читаю список сертификатов с закрытыми ключами из хранилища "MY"
Цитата:

$ ./certmgr -list
Certmgr 1.0 (c) "CryptoPro", 2007-2010.
program for managing certificates, CRLs and stores

=============================================================================
1-------
Issuer : OGRN=
...
PrivateKey Link : Yes. Container: HDIMAGE\\RaUser-8.000\2EA1
=============================================================================

[ErrorCode: 0x00000000]


Попытка получить название контейнера выдает ошибку "The parameter is incorrect."

Код:

while ((pCertContext = CertEnumCertificatesInStore(hCertStore, pCertContext)) != NULL) {
    HCRYPTPROV hCryptProv;

    if(CryptAcquireCertificatePrivateKey(pCertContext, 0, NULL,
          &hCryptProv, &dwKeySpec, &bCallerFreeProv)) {

        CryptGetProvParam(hCryptProv,
            PP_CONTAINER, (BYTE *)pbData, &cbData, 0))
    }
}



Неужели, надо бегать через получение списка всех контейнеров?

CryptGetProvParam(hCryptProv, PP_ENUMCONTAINERS, pbData, &cbData, dwFlags)
Offline Андрей Писарев  
#6 Оставлено : 25 марта 2013 г. 16:33:29(UTC)
Андрей *

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 26.07.2011(UTC)
Сообщений: 12,719
Мужчина
Российская Федерация

Сказал «Спасибо»: 500 раз
Поблагодарили: 2054 раз в 1594 постах
Цитата:
(BYTE *)pbData - ?

сначала null, чтобы узнать размер,
выделить нужный размер...
потом повторный вызов CryptGetProvParam с выделенным буфером ...

Отредактировано пользователем 25 марта 2013 г. 16:35:20(UTC)  | Причина: Не указана

Техническую поддержку оказываем тут
Наша база знаний
Offline miser  
#7 Оставлено : 26 марта 2013 г. 12:07:17(UTC)
miser

Статус: Активный участник

Группы: Участники
Зарегистрирован: 14.03.2011(UTC)
Сообщений: 152
Мужчина
Откуда: Санкт-Петербург

Сказал «Спасибо»: 1 раз
Поблагодарили: 7 раз в 5 постах
Спасибо, частично разобрался.
Есть еще очень интересная ситуация с исследуемым ключиком.

Получаю сертификат из контейнера:
Цитата:

$ ./certmgr -list -cont 'HDIMAGE\\RaUser-8.000\2EA1'
Certmgr 1.0 (c) "CryptoPro", 2007-2010.
program for managing certificates, CRLs and stores

=============================================================================
1-------
Issuer : OGRN=...
Subject : ... CN=Тест Тестович Тестов ...
...
Not valid before: 05/03/2013 07:33:00 UTC
Not valid after : 05/05/2013 07:43:00 UTC
PrivateKey Link : Certificate from container. No link to key
=============================================================================

Тестирую контейнер:
Цитата:

$ ./csptest -keyset -cont 'HDIMAGE\\RaUser-8.000\2EA1' –check
CSP (Type:75) v3.6.5363 KC1 Release Ver:3.6.7363 OS:Linux CPU:AMD64 FastCode:READY:SSSE3.
AcquireContext: OK. HCRYPTPROV: 36359875
GetProvParam(PP_NAME): Crypto-Pro GOST R 34.10-2001 KC1 CSP
Container name: "RaUser-88aa46a2-633f-4f6c-a847-75e6e8cc759c"
Signature key is not available.
Exchange key is available. HCRYPTKEY: 0x2323b13
Keys in container:
exchange key
Total:
[ErrorCode: 0x00000000]

Интересно, показывает, что ключа для подписи нет.
Проверяем подписывание
Цитата:

$ /opt/cprocsp/bin/amd64/csptestf -sfsign -sign -in test.xml -out test.p7b -add -my 'Тест Тестович Тестов'
#0:
Subject: ... CN=Тест Тестович Тестов ...
...
PrivKey: 05.03.2013 07:33:00 - 05.05.2013 07:33:00 (UTC)

A CSP has been acquired.
Source message length: 8870
Calculated signature (or signed message) length: 11896
Signature was done. Signature (or signed message) length: 11896
Output file (test.p7b) has been saved
Total:
[ErrorCode: 0x00000000]

На предыдущем шаге, другой компонент показал, что ключа для подписи нет!

JCP показывает, что сертификат используется для подписывания и авторизации.
JCP подписывает этим сертификатом.

Пишу на С код
Код:

HCRYPTPROV hCryptProv = (HCRYPTPROV) NULL;
HCRYPTKEY hCryptKey = (HCRYPTKEY) NULL;

CryptAcquireContext(&hCryptProv, "HDIMAGE\\\\RaUser-8.000\\2EA1", NULL, 75, 0);
CryptGetUserKey(hCryptProv, AT_SIGNATURE, &hCryptKey);

На последней строке падает ошибка
Цитата:

Error number : 0x8009000d
Error description: Error during CryptGetUserKey for signkey.


Вопрос. Почему csptest и мой код не дают подписывать данные, а csptestf и JCP подписывают?
Offline Андрей Писарев  
#8 Оставлено : 26 марта 2013 г. 12:15:16(UTC)
Андрей *

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 26.07.2011(UTC)
Сообщений: 12,719
Мужчина
Российская Федерация

Сказал «Спасибо»: 500 раз
Поблагодарили: 2054 раз в 1594 постах
вместо AT_SIGNATURE использовать Exchange ...
Техническую поддержку оказываем тут
Наша база знаний
Offline miser  
#9 Оставлено : 26 марта 2013 г. 13:32:51(UTC)
miser

Статус: Активный участник

Группы: Участники
Зарегистрирован: 14.03.2011(UTC)
Сообщений: 152
Мужчина
Откуда: Санкт-Петербург

Сказал «Спасибо»: 1 раз
Поблагодарили: 7 раз в 5 постах
В данном примере, это выход.
Получается, что если AT_SIGNATURE дало ошибку, надо попробовать взять AT_KEYEXCHANGE.

Код:

// Получение закрытого ключа подписи
DWORD providerImpl = AT_SIGNATURE;
if(! CryptGetUserKey(hCryptProv, providerImpl, &hCryptKey)) {
    providerImpl = AT_KEYEXCHANGE;
    CryptGetUserKey(hCryptProv, providerImpl, &hCryptKey);
}
// Определение размера подписи и распределение памяти.
DWORD dwSigLen
CryptSignHash(hCryptHash, providerImpl, NULL, dwFlags, NULL, &dwSigLen);

Как-то не очень.

В примерах производителя такого грязного кода нет.
Offline Андрей Писарев  
#10 Оставлено : 26 марта 2013 г. 13:46:19(UTC)
Андрей *

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 26.07.2011(UTC)
Сообщений: 12,719
Мужчина
Российская Федерация

Сказал «Спасибо»: 500 раз
Поблагодарили: 2054 раз в 1594 постах
Автор: miser Перейти к цитате
В данном примере, это выход.
Получается, что если AT_SIGNATURE дало ошибку, надо попробовать взять AT_KEYEXCHANGE.

Код:

// Получение закрытого ключа подписи
DWORD providerImpl = AT_SIGNATURE;
if(! CryptGetUserKey(hCryptProv, providerImpl, &hCryptKey)) {
    providerImpl = AT_KEYEXCHANGE;
    CryptGetUserKey(hCryptProv, providerImpl, &hCryptKey);
}
// Определение размера подписи и распределение памяти.
DWORD dwSigLen
CryptSignHash(hCryptHash, providerImpl, NULL, dwFlags, NULL, &dwSigLen);

Как-то не очень.

В примерах производителя такого грязного кода нет.



Почему грязного? Anxious

Отредактировано пользователем 26 марта 2013 г. 13:48:58(UTC)  | Причина: Не указана

Техническую поддержку оказываем тут
Наша база знаний
RSS Лента  Atom Лента
Пользователи, просматривающие эту тему
Guest
2 Страницы12>
Быстрый переход  
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.