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

Уведомление

Icon
Error

Опции
К последнему сообщению К первому непрочитанному
Offline eight  
#1 Оставлено : 20 января 2015 г. 16:04:14(UTC)
eight

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

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

Добрый день! Необходимо реализовать вход в систему по ЭЦП, сейчас это работает, но перед тем чтобы пользователь смог войти в систему его сертификат нужно зарегистрировать в системе через КприптоПро. Т.е. каждый человек, желающий войти должен обращаться к администратору, чтобы тот его регистрировал. Сейчас же нужно сделать так, чтобы пользователю не нужно было обращаться к администратору для регистрации сертификата в системе. Это лишнее действие так как есть основная проверка на сервере аутентификации, который проходит каждый пользователь при попытке входа в систему. Сертификат пользователя хранится на рутокене. При регистрации сертификата через криптопро происходит привязка к контейнеру. Ниже приведён код моего решения. Суть в том, чтобы взять первый попавшийся сертификат из рутокена, зарегистрировать его в системе и вот с ним подписать нужные мне данные для аутентификации пользователя.
Но это не работает так как при вызове CryptSignMessage вылетает окно в котором нужно выбрать отсутствующий контейнер!
Не могу понять в чём причина, потому что контейнер-то с которого извлекался сертификат подключён к системе.
Буду рад любой помощи.


Код:

#include <windows.h>
#include <wincrypt.h>
#include <stdio.h>
#include <string>
#include <vector>
#include "WinCryptEx.h"

#pragma comment(lib, "Crypt32.lib")

#define MY_ENCODING_TYPE  (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
#define MAX_BUFFER_SIZE 100000

std::vector<PCCERT_CONTEXT> g_Certificates;

const char secret_phrase[] = "secret phrase";

void logInFile(std::string s) { printf("%s\n", s.c_str()); }

void MyEnumCert()
{
	printf("refreshCertificates\n");

	HCRYPTPROV hProv = 0;
	if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_GOST_2001_DH, CRYPT_VERIFYCONTEXT)) {
		printf("CryptAcquireContext failed\n");
		return;
	}

	DWORD fParam = CRYPT_FIRST;
	DWORD cnt = 0;
	DWORD size = 1000;
	BYTE ContName[1000] = "mini_rutoken\0";
	BYTE* pbCertBlob = 0;
	DWORD dwCertBlob = 0;
	PCCERT_CONTEXT certificate = 0;


	fParam = CRYPT_FIRST;
	while (CryptGetProvParam(hProv, PP_ENUMCONTAINERS, ContName, &size, fParam)) {
		printf("Container name: ");
		printf((char*)ContName);
		printf("\n");

		fParam = CRYPT_NEXT;
		cnt++;
		HCRYPTKEY hKey;
		HCRYPTPROV hProv2;

		std::wstring name(ContName, ContName + size);
		CryptAcquireContextW(&hProv2, name.c_str(), NULL, PROV_GOST_2001_DH, NULL);


		if (!CryptGetUserKey(hProv2, AT_KEYEXCHANGE, &hKey)) {
			printf("CryptGetUserKey failed\n");
			CryptReleaseContext(hProv2, 0);
			continue;
		}

		if (!CryptGetKeyParam(hKey, KP_CERTIFICATE, NULL, &dwCertBlob, NULL)) {
			printf("CryptGetKeyParam failed\n");
			CryptReleaseContext(hProv2, 0);
			continue;
		}

		pbCertBlob = new BYTE[dwCertBlob];
		if (!CryptGetKeyParam(hKey, KP_CERTIFICATE, pbCertBlob, &dwCertBlob, NULL)) {
			printf("Get certificate blob failed\n");
			delete pbCertBlob;
			CryptReleaseContext(hProv2, 0);
			continue;
		}

		CRYPT_KEY_PROV_INFO key;
		key.dwProvType = PROV_GOST_2001_DH;
		key.dwFlags = NULL;
		key.cProvParam = NULL;
		key.rgProvParam = NULL;
		key.dwKeySpec = AT_KEYEXCHANGE;
		certificate = CertCreateCertificateContext(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, pbCertBlob, dwCertBlob);
		if (certificate)
		{
			const int SUBJECT_NAME_SIZE = 512;
			char subjectName[SUBJECT_NAME_SIZE] = "unknown";
			CertGetNameString(certificate,
				CERT_NAME_ATTR_TYPE,
				0,
				szOID_COMMON_NAME,
				subjectName,
				SUBJECT_NAME_SIZE);

			CharToOemA(subjectName, subjectName);

			printf("Certificate received\nPush certificate: %s\n", subjectName);
			//m_certificates.push_back(certificate);
			g_Certificates.push_back(certificate);
			delete pbCertBlob;
			CryptReleaseContext(hProv2, 0);
			continue;
		}
		else
		{
			delete pbCertBlob;
			printf("Error creating certificate context\n");
			CryptReleaseContext(hProv2, 0);
			continue;
		}
	}

	CryptReleaseContext(hProv, 0);
}

const std::string signMessage(PCCERT_CONTEXT pSignerCertContext,
	const BYTE* pbContent,
	const DWORD & cbContent)
{
	if (pSignerCertContext == NULL)
	{
		logInFile("Empty certificate received");
		return "";
	}

	bool result = false;
	CRYPT_SIGN_MESSAGE_PARA SignPara;
	const BYTE *rgpbToBeSigned[1];
	DWORD rgcbToBeSigned[1];
	BYTE pbEncodedBlob[MAX_BUFFER_SIZE];

	ZeroMemory(&SignPara, sizeof CRYPT_SIGN_MESSAGE_PARA);

	SignPara.cbSize = sizeof(CRYPT_SIGN_MESSAGE_PARA);
	SignPara.dwMsgEncodingType = MY_ENCODING_TYPE;
	SignPara.pSigningCert = pSignerCertContext;
	SignPara.HashAlgorithm.pszObjId = (LPSTR)szOID_CP_GOST_R3411;
	SignPara.HashAlgorithm.Parameters.cbData = 0;
	SignPara.pvHashAuxInfo = NULL;
	SignPara.cMsgCert = 1;
	SignPara.rgpMsgCert = &pSignerCertContext;
	SignPara.cMsgCrl = 0;
	SignPara.rgpMsgCrl = NULL;
	SignPara.cAuthAttr = 0;
	SignPara.rgAuthAttr = NULL;
	SignPara.cUnauthAttr = 0;
	SignPara.rgUnauthAttr = NULL;
	SignPara.dwFlags = 0;
	SignPara.dwInnerContentType = 0;

	// Content to be signed
	rgpbToBeSigned[0] = pbContent;
	rgcbToBeSigned[0] = cbContent;

	DWORD cbEncodedBlob = MAX_BUFFER_SIZE;

	logInFile("Start signing");
	BOOL success = CryptSignMessage(
		&SignPara,
		FALSE,                   // fDetachedSignature,
		1,                       // 1 element in array
		rgpbToBeSigned,
		rgcbToBeSigned,
		pbEncodedBlob,
		&cbEncodedBlob
		);

	if (success)
	{
		logInFile("Message successfully signed");
		std::string value(pbEncodedBlob, pbEncodedBlob + cbEncodedBlob);
		return value;
	}
	else
	{
		char errorNumber[100];
		_itoa(GetLastError(), errorNumber, 16);
		logInFile("Message was not signed:");
		logInFile(errorNumber);
		return "";
	}
}

bool addCertToStore(PCCERT_CONTEXT pcert, PCCERT_CONTEXT* pcert_new)
{
	HCERTSTORE hSysStore = NULL;

	hSysStore = CertOpenStore(
		CERT_STORE_PROV_SYSTEM,          // The store provider type
		/*0*/ MY_ENCODING_TYPE,          // The encoding type is not needed
		NULL,                            // Use the default HCRYPTPROV
		CERT_SYSTEM_STORE_LOCAL_MACHINE,  // Set the store location in a registry location
		L"MY"                            // The store name as a Unicode string
		);

	//hSysStore = CertOpenSystemStoreW(0, L"MY");

	if (hSysStore)
		printf("The system store was created successfully.\n");
	else{
		printf("An error occurred during creation of the system store!\n");
		return false;
	}

	BOOL added = CertAddCertificateContextToStore(hSysStore, pcert, CERT_STORE_ADD_ALWAYS, pcert_new);
	//BOOL added = CertAddCertificateContextToStore(hSysStore, pcert, CERT_STORE_ADD_REPLACE_EXISTING, pcert_new);
	//BOOL added = CertAddCertificateContextToStore(hSysStore, pcert, CERT_STORE_ADD_USE_EXISTING, pcert_new);

	//BOOL added = CertAddCertificateLinkToStore(hSysStore, pcert, CERT_STORE_ADD_REPLACE_EXISTING /*CERT_STORE_ADD_ALWAYS*/, pcert_new);

	if (added)
		printf("cert was added in system successfully, last error %d ( 0x%x ) \n", GetLastError(), GetLastError());
	else
		printf("cert wasn't added in system\n");

	//CertCloseStore(hSysStore, CERT_CLOSE_STORE_CHECK_FLAG);
	return added;
}

int main()
{
	MyEnumCert();

	if (!g_Certificates.empty())
	{
		printf("Found certificates %d\n", g_Certificates.size());
		PCCERT_CONTEXT pcert = g_Certificates[0], pcert_new, pcert_old = g_Certificates[0];
		const DWORD size = sizeof secret_phrase;

		if ( addCertToStore(pcert, &pcert_new) )
		{
			pcert = pcert_new;
			printf("change certificates\n");
			const std::string s = signMessage(pcert, (const BYTE*)secret_phrase, size);

			if (!s.empty())
			{
				std::string input(secret_phrase);
				printf("Input data %d\n\nData: ", input.size());
				for (int i = 0; i < s.length() && i < 10; i++) printf("%x:", input.data()[i]);
				printf("\n\nSize of signed data %d\n\nData: ", s.size());
				for (int i = 0; i < s.length() && i < 10; i++) printf("%x:", s.data()[i]);
			}

			//if (!CertDeleteCertificateFromStore(pcert_old)) printf("certificate wasn't removed\n");
			//if (!CertDeleteCertificateFromStore(pcert_new)) printf("2certificate wasn't removed\n");
			
		} else {
			printf("couldn't add!\n");
		}
	}

	printf("\n\npress any key to exit.\n");
	getchar();
	return 0;
}
Offline Максим Коллегин  
#2 Оставлено : 21 января 2015 г. 7:29:17(UTC)
Максим Коллегин

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

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

Сказал «Спасибо»: 37 раз
Поблагодарили: 719 раз в 623 постах
Очень странное решение.
Не нужно устанавливать сертификат пользователя вообще. Достаточно установить ссылку на закрытый ключ контексту сертификата перед подписанием, а вы этого не делаете вообще (http://www.cryptopro.ru/forum2/default.aspx?q=cryptopro/forum2/default.aspx&g=posts&t=54#post183)
Чтобы перечислить контейнеры только с токена, можно открыть криптопровайдер по имени считывателя: \\.\Reader_name

Отредактировано пользователем 21 января 2015 г. 7:30:56(UTC)  | Причина: Не указана

Знания в базе знаний, поддержка в техподдержке
Offline eight  
#3 Оставлено : 21 января 2015 г. 19:05:11(UTC)
eight

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

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

Вчера нашёл решение данной проблемы. Импортировал сертификат и подписывал, но там была какая-то непонтная привязка с контейнеру. Решил проблему перепривязыванием.

Код:

#include <windows.h>
#include <wincrypt.h>
#include <stdio.h>
#include <string>
#include <vector>
#include <map>
#include "WinCryptEx.h"

#pragma comment(lib, "Crypt32.lib")

#define MY_ENCODING_TYPE  (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
#define MAX_BUFFER_SIZE 100000

typedef std::vector< std::pair<PCCERT_CONTEXT /* certificate context */, std::wstring /* container name */> > Certificates;

std::vector<PCCERT_CONTEXT> g_Certificates;

std::vector< std::pair<PCCERT_CONTEXT /* certificate context */, std::wstring /* container name */> > gLoadedCertificates;
std::wstring g_container;

const char secret_phrase[] = "secret phrase";

void logInFile(std::string s) { printf("%s\n", s.c_str()); }

bool addCertToStore(PCCERT_CONTEXT pcert, PCCERT_CONTEXT* pcert_new)
{
	HCERTSTORE hSysStore = NULL;

	hSysStore = CertOpenStore(
		CERT_STORE_PROV_SYSTEM,          // The store provider type
		/*0*/ MY_ENCODING_TYPE,          // The encoding type is not needed
		NULL,                            // Use the default HCRYPTPROV
		CERT_SYSTEM_STORE_LOCAL_MACHINE,  // Set the store location in a registry location
		L"MY"                            // The store name as a Unicode string
		);

	//hSysStore = CertOpenSystemStoreW(0, L"MY");

	if (hSysStore)
		printf("The system store was created successfully.\n");
	else{
		printf("An error occurred during creation of the system store!\n");
		return false;
	}

	//BOOL added = CertAddCertificateContextToStore(hSysStore, pcert, CERT_STORE_ADD_ALWAYS, pcert_new);
	//BOOL added = CertAddCertificateContextToStore(hSysStore, pcert, CERT_STORE_ADD_REPLACE_EXISTING, pcert_new);
	BOOL added = CertAddCertificateContextToStore(hSysStore, pcert, CERT_STORE_ADD_USE_EXISTING, pcert_new);

	//BOOL added = CertAddCertificateLinkToStore(hSysStore, pcert, CERT_STORE_ADD_REPLACE_EXISTING /*CERT_STORE_ADD_ALWAYS*/, pcert_new);

	if (added)
		printf("cert was added in system successfully, last error %d ( 0x%x ) \n", GetLastError(), GetLastError());
	else
		printf("cert wasn't added in system\n");

	CertCloseStore(hSysStore, CERT_CLOSE_STORE_CHECK_FLAG);
	return added;
}

void MyEnumCert()
{
	//
	// 1. Acquire context to enumerate containers.
	//
	HCRYPTPROV hProv = 0;
	if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_GOST_2001_DH, CRYPT_VERIFYCONTEXT)) {
		printf("CryptAcquireContext failed\n");
		return;
	}

	DWORD fParam = CRYPT_FIRST;
	DWORD cnt = 0;
	DWORD size = 1000;
	BYTE ContName[1000] = "mini_rutoken\0";
	BYTE* pbCertBlob = 0;
	DWORD dwCertBlob = 0;
	PCCERT_CONTEXT certificate = 0;

	fParam = CRYPT_FIRST;

	//
	// 2. Enumerate containers and collect all CERT_CONTEXTs.
	//
	while (CryptGetProvParam(hProv, PP_ENUMCONTAINERS, ContName, &size, fParam))
	{
		printf("Container name: %s\n", ContName);

		fParam = CRYPT_NEXT;
		cnt++;
		HCRYPTKEY hKey;
		HCRYPTPROV hProv2;

		//
		// 3. Start work with a container.
		//
		std::wstring container(ContName, ContName + size);
		CryptAcquireContextW(&hProv2, container.c_str(), NULL, PROV_GOST_2001_DH, NULL);

		if (!CryptGetUserKey(hProv2, AT_KEYEXCHANGE, &hKey)) {
			printf("CryptGetUserKey failed\n");
			CryptReleaseContext(hProv2, 0);
			continue;
		}

		//
		// Get size of certificate.
		//
		if (!CryptGetKeyParam(hKey, KP_CERTIFICATE, NULL, &dwCertBlob, NULL)) {
			printf("CryptGetKeyParam failed\n");
			CryptReleaseContext(hProv2, 0);
			continue;
		}

		//
		// Read certificate.
		//
		pbCertBlob = new BYTE[dwCertBlob];
		if (!CryptGetKeyParam(hKey, KP_CERTIFICATE, pbCertBlob, &dwCertBlob, NULL)) {
			printf("Get certificate blob failed\n");
			delete pbCertBlob;
			CryptReleaseContext(hProv2, 0);
			continue;
		}

		//
		// Create certificate context from just read binary data.
		//
		certificate = CertCreateCertificateContext( MY_ENCODING_TYPE /*PKCS_7_ASN_ENCODING | X509_ASN_ENCODING*/ , pbCertBlob, dwCertBlob);
		if (certificate)
		{
			const int SUBJECT_NAME_SIZE = 512;
			char subjectName[SUBJECT_NAME_SIZE] = "unknown";
			CertGetNameString(certificate, CERT_NAME_ATTR_TYPE, 0, szOID_COMMON_NAME, subjectName, SUBJECT_NAME_SIZE);
			CharToOemA(subjectName, subjectName);
			printf("Certificate received\nPush certificate: %s\n", subjectName);

			//
			// Save certificate with binding to container.
			//
			gLoadedCertificates.push_back(std::pair<PCCERT_CONTEXT, std::wstring>(certificate, container));

			//g_Certificates.push_back(certificate);
			delete pbCertBlob;
			CryptReleaseContext(hProv2, 0);
			continue;
		}
		else
		{
			delete pbCertBlob;
			printf("Error creating certificate context\n");
			CryptReleaseContext(hProv2, 0);
			continue;
		}
	}

	CryptReleaseContext(hProv, 0);
}

const std::string signMessage(PCCERT_CONTEXT pSignerCertContext,
	const BYTE* pbContent,
	const DWORD & cbContent)
{
	if (pSignerCertContext == NULL)
	{
		logInFile("Empty certificate received");
		return "";
	}

	bool result = false;
	CRYPT_SIGN_MESSAGE_PARA SignPara;
	const BYTE *rgpbToBeSigned[1];
	DWORD rgcbToBeSigned[1];
	BYTE pbEncodedBlob[MAX_BUFFER_SIZE];

	ZeroMemory(&SignPara, sizeof CRYPT_SIGN_MESSAGE_PARA);

	SignPara.cbSize = sizeof(CRYPT_SIGN_MESSAGE_PARA);
	SignPara.dwMsgEncodingType = MY_ENCODING_TYPE;
	SignPara.pSigningCert = pSignerCertContext;
	SignPara.HashAlgorithm.pszObjId = (LPSTR)szOID_CP_GOST_R3411;
	SignPara.HashAlgorithm.Parameters.cbData = 0;
	SignPara.pvHashAuxInfo = NULL;
	SignPara.cMsgCert = 1;
	SignPara.rgpMsgCert = &pSignerCertContext;
	SignPara.cMsgCrl = 0;
	SignPara.rgpMsgCrl = NULL;
	SignPara.cAuthAttr = 0;
	SignPara.rgAuthAttr = NULL;
	SignPara.cUnauthAttr = 0;
	SignPara.rgUnauthAttr = NULL;
	SignPara.dwFlags = 0;
	SignPara.dwInnerContentType = 0;

	// Content to be signed
	rgpbToBeSigned[0] = pbContent;
	rgcbToBeSigned[0] = cbContent;

	DWORD cbEncodedBlob = MAX_BUFFER_SIZE;

	logInFile("Start signing");
	BOOL success = CryptSignMessage(
		&SignPara,
		FALSE,                   // fDetachedSignature,
		1,                       // 1 element in array
		rgpbToBeSigned,
		rgcbToBeSigned,
		pbEncodedBlob,
		&cbEncodedBlob
		);

	if (success)
	{
		logInFile("Message successfully signed");
		std::string value(pbEncodedBlob, pbEncodedBlob + cbEncodedBlob);
		return value;
	}
	else
	{
		char errorNumber[100];
		_itoa(GetLastError(), errorNumber, 16);
		logInFile("Message was not signed:");
		logInFile(errorNumber);
		return "";
	}
}



int main()
{
	MyEnumCert();

	if (!gLoadedCertificates.empty())
	{
		printf("Found certificates %d\n", gLoadedCertificates.size());
		PCCERT_CONTEXT pcert = gLoadedCertificates[0].first;
		std::wstring container = gLoadedCertificates[0].second;
		const DWORD size = sizeof secret_phrase;

		//////////////////////////////////////////////////////////////////////////
		CRYPT_KEY_PROV_INFO key;
		ZeroMemory(&key, sizeof CRYPT_KEY_PROV_INFO);
		key.dwProvType = PROV_GOST_2001_DH;
		key.dwFlags = NULL;
		key.cProvParam = NULL;
		key.rgProvParam = NULL;
		key.dwKeySpec = AT_KEYEXCHANGE;
		key.pwszContainerName = (LPWSTR)container.c_str();
		DWORD sz = sizeof(CRYPT_KEY_PROV_INFO);
		BOOL success = CertSetCertificateContextProperty(pcert, CERT_KEY_PROV_INFO_PROP_ID, CERT_STORE_NO_CRYPT_RELEASE_FLAG, (CRYPT_KEY_PROV_INFO*)&key);
		if (success)
		{
			printf("change certificates\n");
			const std::string s = signMessage(pcert, (const BYTE*)secret_phrase, size);

			if (!s.empty())
			{
				std::string input(secret_phrase);
				printf("Input data %d\n\nData: ", input.size());
				for (int i = 0; i < s.length() && i < 10; i++) printf("%x:", input.data()[i]);
				printf("\n\nSize of signed data %d\n\nData: ", s.size());
				for (int i = 0; i < s.length() && i < 10; i++) printf("%x:", s.data()[i]);
			}
		} else {
			printf("Error. Couldn't bind  certificate to container %ws\n", container);
		}
	}

	printf("\n\npress any key to exit.\n");
	getchar();
	return 0;
}
RSS Лента  Atom Лента
Пользователи, просматривающие эту тему
Guest
Быстрый переход  
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.