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

Уведомление

Icon
Error

3 Страницы123>
Опции
К последнему сообщению К первому непрочитанному
Offline NKNikolai  
#1 Оставлено : 4 октября 2018 г. 17:48:31(UTC)
NKNikolai

Статус: Новичок

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

Сказал(а) «Спасибо»: 6 раз
Добрый день.

Нужно установить сертификат из файла в контейнер с приватной частью.
Если это делать вручную через CryptoPro, то все работает.

Пытаюсь автоматизировать процесс (С++).

Код приведен ниже.
Отрабатывает до шага 7 - Map key and certificate.
Вызов CryptSetKeyParam возвращает ошибку 'Неправильный параметр набора ключей'.

Подскажите, корректен ли мой алгоритм? Последовательность шагов такая:

0.) Open cert. store.
1.) Construct PCCERT_CONTEXT from dataCert.
2.) Create new certificate from the encoded part of an available certificate.
3.) Fill provider info
4.) Associate the container with certificate
5.) Get access to container
6.) Get key
7.) Map key and certificate. <- Вы
8.) Add certificate to store.

Не нужно ли сначала добавлять сертификат в контейнер, и уже потом его модифицировать?
Сам сертификат по идее валидный - у меня получалось его через
CertAddCertificateContextToStore добавлять в CryptoPro (правда, не в конкретно нужный мне контейнер).

На форуме нашел вот этот пост: https://www.cryptopro.ru....aspx?g=posts&t=6125
Код очень похож на мой, но до проблем с использованием установленного сертификата я не дошел.

Код:

//! dataCert - содержимое сертификата.
PCCERT_CONTEXT installCert(const std::string &containerName, const std::string &dataCert, int providerType)
{
	// ----------------------------------------------------------------
	// 0.) Open cert. store.
	HCERTSTORE hCertStore = CertOpenSystemStore(0, _T("MY"));
	if (!hCertStore)
	{
		const auto message = logLastErrorMesage("CertOpenSystemStore");
		throw std::runtime_error("can't install cert: " + message);
	}

	// ----------------------------------------------------------------
	//  1.) Construct PCCERT_CONTEXT from dataCert.

	CERT_BLOB certBlob;
	certBlob.pbData = (BYTE*)dataCert.data();
	certBlob.cbData = dataCert.size();
	PCCERT_CONTEXT pCertContext = NULL;

	PCCERT_CONTEXT pExtCertCtx = 0;
	if (!CryptQueryObject(CERT_QUERY_OBJECT_BLOB, &certBlob, CERT_QUERY_CONTENT_FLAG_CERT,
		CERT_QUERY_FORMAT_FLAG_ALL, 0, NULL, NULL, NULL, NULL, NULL, (const void **)&pExtCertCtx))
	{
		const auto message = logLastErrorMesage("CryptQueryObject");
		throw std::runtime_error("can't install cert: " + message);
	}

	// ------------------------------------------------------------------ 
	//  2.) Create a new certificate from the encoded part of an available certificate.
	pCertContext = CertCreateCertificateContext(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, // The encoding type
												pExtCertCtx->pbCertEncoded,   // The encoded data from the certificate retrieved
												pExtCertCtx->cbCertEncoded);  // The length of the encoded data
	if (!pCertContext)
	{
		const auto message = logLastErrorMesage("CertCreateCertificateContext");
		throw std::runtime_error("can't install cert: " + message);
	}

	// ------------------------------------------------------------------ 
	//  3.) Fill provider info
	CRYPT_KEY_PROV_INFO providerInfo;
	memset(&providerInfo, 0, sizeof(providerInfo));
	providerInfo.pwszContainerName = (wchar_t*)std::wstring(toWString(containerName)).c_str();
	providerInfo.dwProvType = providerType;
	providerInfo.dwKeySpec = AT_KEYEXCHANGE;

	// ------------------------------------------------------------------ 
	// 4.) Associate the container with our certificate
	if (!CertSetCertificateContextProperty(pCertContext, CERT_KEY_PROV_INFO_PROP_ID, 0, &providerInfo))
	{
		const auto message = logLastErrorMesage("CertSetCertificateContextProperty");
		throw std::runtime_error("can't install cert: " + message);
	}

	// ------------------------------------------------------------------ 
	// 5.) Get access to container
	HCRYPTPROV hCryptProv = NULL;
	if (!CryptAcquireContext(
		&hCryptProv,                 // handle to the CSP
		utils::utf8_decode(containerName).c_str(),                  // container name 
		NULL,                        // use the default provider
		providerType,                // provider type
		0)							 // flag values
		)
	{
		const auto message = logLastErrorMesage("CryptAcquireContext");
		throw std::runtime_error("can't access cypto provider/container: " + message);
	}

	// ------------------------------------------------------------------ 
	// 6.) Get key
	HCRYPTKEY hKey = NULL;
	if (!CryptGetUserKey(hCryptProv, AT_KEYEXCHANGE, &hKey))
	{
		const auto message = logLastErrorMesage("CryptGetUserKey");
		throw std::runtime_error("can't get key for certificate: " + message);
	}

	// ------------------------------------------------------------------ 
	// 7.) Map key and certificate.
	if (!CryptSetKeyParam(
		hKey,
		KP_CERTIFICATE,
		certBlob.pbData,
		0))
	{
		const auto message = logLastErrorMesage("CryptSetKeyParam");
		throw std::runtime_error("can't set key cert param: " + message);
	}

	// ------------------------------------------------------------------ 
	// 8.) Add certificate to store.

	if (!CertAddCertificateContextToStore(hCertStore, pCertContext, CERT_STORE_ADD_ALWAYS, 0)) 
	{
		const auto message = logLastErrorMesage("CertAddCertificateContextToStore");
		throw std::runtime_error("can't install cert: " + message);
	}

	// ------------------------------------------------------------------ 
	// ------------------------------------------------------------------ 
	displayCertInStore(L"MY");

	/* Free resources, catch exceptions.
		...
	*/

	return pCertContext;
}

Отредактировано пользователем 4 октября 2018 г. 17:50:10(UTC)  | Причина: Не указана

Offline Максим Коллегин  
#2 Оставлено : 4 октября 2018 г. 18:23:00(UTC)
Максим Коллегин

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

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

Сказал «Спасибо»: 32 раз
Поблагодарили: 704 раз в 613 постах
Передайте в CryptSetProvParam pCertContext->pbCertEncoded
Знания в базе знаний, поддержка в техподдержке
thanks 1 пользователь поблагодарил Максим Коллегин за этот пост.
NKNikolai оставлено 04.10.2018(UTC)
Offline NKNikolai  
#3 Оставлено : 4 октября 2018 г. 19:28:52(UTC)
NKNikolai

Статус: Новичок

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

Сказал(а) «Спасибо»: 6 раз
Автор: Максим Коллегин Перейти к цитате
Передайте в CryptSetProvParam pCertContext->pbCertEncoded


Спасибо, попробовал.
На этом же вызове теперь получаю 'Плохие данные'.

Сам pCertContext содержит корректные данные:
certContext->pCertInfo->Issuer, certContext->pCertInfo->SerialNumber,...
pCertContext->pbCertEncoded можно как-то 'проверить'?
Offline Андрей Писарев  
#4 Оставлено : 4 октября 2018 г. 20:22:29(UTC)
Андрей *

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

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

Сказал «Спасибо»: 494 раз
Поблагодарили: 2035 раз в 1579 постах
Цитата:
certBlob.pbData,


Почему не из контекста сертификата?
Техническую поддержку оказываем тут
Наша база знаний
thanks 1 пользователь поблагодарил Андрей * за этот пост.
NKNikolai оставлено 05.10.2018(UTC)
Offline Андрей Писарев  
#5 Оставлено : 4 октября 2018 г. 20:27:52(UTC)
Андрей *

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

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

Сказал «Спасибо»: 494 раз
Поблагодарили: 2035 раз в 1579 постах
В общем в шаге 7) (86 строка) нужно использовать из 2). строка 33 - pCertContext pbCertEncoded
А не то, что в certBlob.pbData


Техническую поддержку оказываем тут
Наша база знаний
thanks 1 пользователь поблагодарил Андрей * за этот пост.
NKNikolai оставлено 05.10.2018(UTC)
Offline Андрей Писарев  
#6 Оставлено : 4 октября 2018 г. 20:32:22(UTC)
Андрей *

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

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

Сказал «Спасибо»: 494 раз
Поблагодарили: 2035 раз в 1579 постах
Автор: NKNikolai Перейти к цитате
Автор: Максим Коллегин Перейти к цитате
Передайте в CryptSetProvParam pCertContext->pbCertEncoded


Спасибо, попробовал.
На этом же вызове теперь получаю 'Плохие данные'.

Сам pCertContext содержит корректные данные:
certContext->pCertInfo->Issuer, certContext->pCertInfo->SerialNumber,...
pCertContext->pbCertEncoded можно как-то 'проверить'?


Увидел ответ.

А этот сертификат - успешно устанавливается через панель управления КриптоПРО CSP?

Через автопоиск - находит контейнер и записывыается в него?

Техническую поддержку оказываем тут
Наша база знаний
thanks 1 пользователь поблагодарил Андрей * за этот пост.
NKNikolai оставлено 05.10.2018(UTC)
Offline Андрей Писарев  
#7 Оставлено : 4 октября 2018 г. 21:30:09(UTC)
Андрей *

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

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

Сказал «Спасибо»: 494 раз
Поблагодарили: 2035 раз в 1579 постах
Автор: NKNikolai Перейти к цитате

На этом же вызове теперь получаю 'Плохие данные'.


На ПК только КриптоПРО CSP и контейнер сгенерирован через КриптоПРО CSP?
Техническую поддержку оказываем тут
Наша база знаний
thanks 1 пользователь поблагодарил Андрей * за этот пост.
NKNikolai оставлено 05.10.2018(UTC)
Offline two_oceans  
#8 Оставлено : 5 октября 2018 г. 6:59:43(UTC)
two_oceans

Статус: Эксперт

Группы: Участники
Зарегистрирован: 05.03.2015(UTC)
Сообщений: 1,602
Российская Федерация
Откуда: Иркутская область

Сказал(а) «Спасибо»: 110 раз
Поблагодарили: 393 раз в 366 постах
Суммируя: как я понял, dataCert и certBlob содержат сертификат неизвестно в каком формате, его переформатирует CryptQueryObject в контекст сертификата? Вопрос - какой смысл заложен в 2) создание одного контекста сертификата по данным из такого же контекста сертификата?
Цитата:
pCertContext->pbCertEncoded можно как-то 'проверить'?
Конечно, возможна визуальная проверка. Если записать из буфера по адресу pCertContext->pbCertEncoded в файл c расширением .cer pCertContext->cbCertEncoded байт (ничего не добавляя впереди и позади) это будет как раз сертификат в формате DER и он должен нормально открываться в windows двойным щелчком и нормально показывать все свойства сертификата. Если выходит ошибка, то можно посмотреть разными программами для работы с кодированием ASN.1, в том числе через openssl:
Код:
openssl x509 -in 1.cer -inform DER -text
openssl req -in 1.cer -inform DER -text
openssl asn1parse -in 1.cer -inform DER
первая команда для сертификатов, вторая для запросов на сертификат (для обычных сертификатов не работает, но при ошибке не мешает попробовать), третья общая для кодирования ASN.1. Openssl не декодирует некоторые свойства сертификата (выводятся в двоичном виде), но для проверки должно хватить и поддерживаемых свойств.

Отредактировано пользователем 5 октября 2018 г. 7:21:06(UTC)  | Причина: уточнение

thanks 1 пользователь поблагодарил two_oceans за этот пост.
NKNikolai оставлено 05.10.2018(UTC)
Offline NKNikolai  
#9 Оставлено : 5 октября 2018 г. 14:07:46(UTC)
NKNikolai

Статус: Новичок

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

Сказал(а) «Спасибо»: 6 раз
Автор: Андрей Писарев Перейти к цитате
Автор: NKNikolai Перейти к цитате
Автор: Максим Коллегин Перейти к цитате
Передайте в CryptSetProvParam pCertContext->pbCertEncoded


Спасибо, попробовал.
На этом же вызове теперь получаю 'Плохие данные'.

Сам pCertContext содержит корректные данные:
certContext->pCertInfo->Issuer, certContext->pCertInfo->SerialNumber,...
pCertContext->pbCertEncoded можно как-то 'проверить'?


Увидел ответ.

А этот сертификат - успешно устанавливается через панель управления КриптоПРО CSP?

Через автопоиск - находит контейнер и записывыается в него?



Да, если ставить через панель, все окей. Через автопоиск находит.

Автор: Андрей Писарев Перейти к цитате
Автор: NKNikolai Перейти к цитате

На этом же вызове теперь получаю 'Плохие данные'.


На ПК только КриптоПРО CSP и контейнер сгенерирован через КриптоПРО CSP?


Да.

По поводу pExtCertCtx и pCertContext - возможно, один из них и не нужен. Проводил эксперименты, оба дают 'Плохие данные'.

Проверю содержимое, как посоветовали. Может, все-таки загружаю неправильно.
Хотя тогда, по идее, certContext->pCertInfo->Issuer, certContext->pCertInfo->SerialNumber не содержали бы корректные данные.
Offline NKNikolai  
#10 Оставлено : 8 октября 2018 г. 19:30:03(UTC)
NKNikolai

Статус: Новичок

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

Сказал(а) «Спасибо»: 6 раз
UPD: пока состояние такое:

1.) Похоже, что с загруженным в pCertContext сертификатом все в порядке - если добавлять pCertContext или pExtCertCtx через CertAddCertificateContextToStore без вызова CryptSetKeyParam,
то он виден в панели CryptoPro CSP (но найти его через контейнер с приватным ключом нельзя - ошибка 'в контейнере закрытого ключа отсутствуют сертификаты').
Через openssl свойства также просматриваются.

2.) CryptSetKeyParam:
- При передаче pCertContext->pbCertEncoded или pExtCertCtx->pbCertEncoded возвращается ошибка 'Плохие данные'.
- При передаче certBlob.pbData - 'Неправильный параметр набора ключей'
Если вызов убрать, код отрабатывает (см. пункт 1).
RSS Лента  Atom Лента
Пользователи, просматривающие эту тему
3 Страницы123>
Быстрый переход  
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.