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

Уведомление

Icon
Error

Опции
К последнему сообщению К первому непрочитанному
Offline manigu  
#1 Оставлено : 21 августа 2014 г. 11:02:59(UTC)
manigu

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

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

Сказал(а) «Спасибо»: 21 раз
Здравствуйте, у меня видимо каша в голове. Пытаюсь создать контейнер и запрос на сертификат. Я так понимаю сначала создается контейнер и пара, затем создается запрос на сертификат?
Контейнер создаётся, ключ подписи (AT_SIGNATURE) присутствует, а вот с ключом обмена (AT_KEYEXCHANGE) проблема, его нет.
Вот мой код.

MakeContainer.h
Код:

#include "stdafx.h"
#include <stdio.h>
#include <windows.h>
#include <wincrypt.h>
#include <WinCryptEx.h>
#include <CertEnroll.h>

class MakeContainer {
private:
	LPCWSTR ProviderName = L"Crypto-Pro GOST R 34.10-2001 Cryptographic Service Provider"; //Название криптопровайдера
	HCRYPTPROV hCryptProv = 0;        // Дескриптор контекста  критографического провайдера.
	HCRYPTKEY hKey = 0;
	LPSTR pszUserName;
	DWORD dwUserNameLen;
	LPCWSTR UserName = L"test"; // имя контейнера

public:
	MakeContainer(HCRYPTPROV hCP, HCRYPTKEY hK) {
		hCryptProv = hCP;
		hKey = hK;
	}

	MakeContainer() {
		hCryptProv = 0;
		hKey = 0;
	}

	//проверка наличия контейнера с таким именем
	bool isContainer() {
		if (CryptAcquireContext(&hCryptProv, UserName, ProviderName, 75, CRYPT_SILENT))
		{
			printf("A cryptcontext with the %s key container has been acquired.\n", UserName);
			return true;
		}
		else
		{
			printf("A cryptcontext with the %s key container not has been acquired.\n", UserName);
			return false;
		}
	}

	//Создание нового контейнера
	void createNewContainer() {
		if (!CryptAcquireContext(
			&hCryptProv,
			UserName,
			ProviderName,
			75,
			CRYPT_NEWKEYSET))
		{
			HandleError("Could not create a new key container.\n");
		}
		printf("A new key container has been created.\n");
	}

	//Вернуть имя контейнера
	void getContainerName() {
		// Криптографический контекст с ключевым контейнером доступен. Получение
		// имени ключевого контейнера. 
		if (!CryptGetProvParam(
			hCryptProv,               // Дескриптор CSP
			PP_CONTAINER,             // Получение имени ключевого контейнера
			NULL,                     // Указатель на имя ключевого контейнера
			&dwUserNameLen,           // Длина имени
			0))
		{
			// Ошибка получении имени ключевого контейнера
			HandleError("error occurred getting the key container name.");
		}

		// Лучше использовать auto_ptr:
		//std::auto_ptr<char> aptrUserName(new char[dwUserNameLen+1]);
		//szUserName = aptrUserName.get();
		pszUserName = (char *)malloc((dwUserNameLen + 1));

		if (!CryptGetProvParam(
			hCryptProv,               // Дескриптор CSP
			PP_CONTAINER,             // Получение имени ключевого контейнера
			(LPBYTE)pszUserName,      // Указатель на имя ключевого контейнера
			&dwUserNameLen,           // Длина имени
			0))
		{
			// Ошибка получении имени ключевого контейнера
			free(pszUserName);
			HandleError("error occurred getting the key container name.");
		}

		printf("A crypto context has been acquired and \n");
		printf("The name on the key container is %s\n\n", pszUserName);
	}

	void getUserKeySignature() {
		// Контекст с ключевым контейнером доступен,
		// попытка получения дескриптора ключа подписи
		if (CryptGetUserKey(hCryptProv, AT_SIGNATURE, &hKey))
		{
			printf("A signature key is available.\n");
		}
		else
		{
			printf("No signature key is available.\n");

			// Ошибка в том, что контейнер не содержит ключа.
			if (!(GetLastError() == (DWORD)NTE_NO_KEY))
				HandleError("An error other than NTE_NO_KEY getting signature key.\n");

			// Создание подписанной ключевой пары. 
			printf("The signature key does not exist.\n");
			printf("Creating a signature key pair...\n");

			if (!CryptGenKey(
				hCryptProv,
				AT_SIGNATURE,
				0,
				&hKey))
			{
				HandleError("Error occurred creating a signature key.\n");
			}
			printf("Created a signature key pair.\n");

		}
	}

	void getUserKeyExchange() {
		// Получение ключа обмена: AT_KEYEXCHANGE
		if (CryptGetUserKey(
			hCryptProv,
			AT_KEYEXCHANGE,
			&hKey))
		{
			printf("An exchange key exists. \n");
		}
		else
		{
			printf("No exchange key is available.\n");
		}
	}

	static void HandleError(char *s) {
		printf(s);
	}
};


main.c
Код:

#include "stdafx.h"
#include "MakeContainer.h"

int _tmain(int argc, _TCHAR* argv[])
{
	MakeContainer a;

	if (!a.isContainer()) {
		a.createNewContainer();
	}

	a.getContainerName();
	a.getUserKeySignature();
	a.getUserKeyExchange();
	//a.createRequest();

	system("pause");
	return 0;
}


В ответ получаю "A signature key is available." и "No exchange key is available."
Заранее спасибо.

Offline Kirill Sobolev  
#2 Оставлено : 21 августа 2014 г. 11:20:27(UTC)
Кирилл Соболев

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

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

Поблагодарили: 177 раз в 168 постах
Все правильно.
У Вас в коде создается только ключ подписи.
Код:
            if (!CryptGenKey(
                hCryptProv,
                AT_SIGNATURE,
                0,
                &hKey))
            {
                HandleError("Error occurred creating a signature key.\n");
            }

Если нужно - создавайте ключ обмена аналогично.
Техническую поддержку оказываем тут
Наша база знаний
thanks 1 пользователь поблагодарил Кирилл Соболев за этот пост.
manigu оставлено 21.08.2014(UTC)
Offline manigu  
#3 Оставлено : 21 августа 2014 г. 12:21:07(UTC)
manigu

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

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

Сказал(а) «Спасибо»: 21 раз
Автор: Kirill Sobolev Перейти к цитате
Все правильно.
У Вас в коде создается только ключ подписи.
Код:
            if (!CryptGenKey(
                hCryptProv,
                AT_SIGNATURE,
                0,
                &hKey))
            {
                HandleError("Error occurred creating a signature key.\n");
            }

Если нужно - создавайте ключ обмена аналогично.


Спасибо, не заметил.
Теперь пытаюсь создать запрос на сертификат, получаю ошибку "8009000d".
За основу взял пример с msdn

Код:

#define CERT_SUBJECT_NAME "test"
#define MY_ENCODING_TYPE  (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
#pragma comment(lib, "crypt32.lib")

void createRequest() {
		
		CERT_RDN_ATTR rgNameAttr[] = {
			"2.5.4.3",                             // pszObjId 
			CERT_RDN_PRINTABLE_STRING,             // dwValueType
			strlen(CERT_SUBJECT_NAME),             // value.cbData
			(BYTE*)CERT_SUBJECT_NAME };

		CERT_RDN rgRDN[] = {1, &rgNameAttr[0] };
		CERT_NAME_INFO Name = {1, rgRDN };

		CERT_REQUEST_INFO  CertReqInfo;
		CERT_NAME_BLOB  SubjNameBlob;
		DWORD  cbNameEncoded;
		BYTE*  pbNameEncoded;
		DWORD  cbPublicKeyInfo;
		CERT_PUBLIC_KEY_INFO*  pbPublicKeyInfo;
		DWORD  cbEncodedCertReqSize;
		CRYPT_OBJID_BLOB  Parameters;
		CRYPT_ALGORITHM_IDENTIFIER  SigAlg;
		BYTE*  pbSignedEncodedCertReq;
		char*  pSignedEncodedCertReqBlob;

		if (CryptEncodeObject(
			MY_ENCODING_TYPE,     // Encoding type
			X509_NAME,            // Structure type
			&Name,                // Address of CERT_NAME_INFO structure
			NULL,                 // pbEncoded
			&cbNameEncoded))      // pbEncoded size
		{
			printf("The first call to CryptEncodeObject succeeded. \n");
		}
		else
		{
			MyHandleError("The first call to CryptEncodeObject failed. \nA public/private key pair may not exit in the container. \n");
		}

		if (!(pbNameEncoded = (BYTE*)malloc(cbNameEncoded)))
			MyHandleError("The pbNamencoded malloc operation failed. \n");

		if (CryptEncodeObject(
			MY_ENCODING_TYPE,    // Encoding type
			X509_NAME,           // Structure type
			&Name,               // Address of CERT_NAME_INFO structure
			pbNameEncoded,       // pbEncoded
			&cbNameEncoded))     // pbEncoded size
		{
			printf("The object is encoded. \n");
		}
		else
		{
			free(pbNameEncoded);
			MyHandleError("The second call to CryptEncodeObject failed. \n");
		}

		SubjNameBlob.cbData = cbNameEncoded;
		SubjNameBlob.pbData = pbNameEncoded;
		CertReqInfo.Subject = SubjNameBlob;

		CertReqInfo.cAttribute = 0;
		CertReqInfo.rgAttribute = NULL;
		CertReqInfo.dwVersion = CERT_REQUEST_V1;
		
		if (CryptAcquireContext(
			&hCryptProv,        // Address for handle to be returned.
			NULL,               // Use the current user's logon name.
			NULL,               // Use the default provider.
			PROV_RSA_FULL,      // Need to both encrypt and sign.
			NULL))              // No flags needed.
		{
			printf("A cryptographic provider has been acquired. \n");
		}
		else
		{
			free(pbNameEncoded);
			MyHandleError("CryptAcquireContext failed. \n");
		}
		

		DWORD dwLen = 0;
		if (CryptExportPublicKeyInfo(hCryptProv, AT_KEYEXCHANGE, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, NULL, &dwLen)) {
			MyHandleError("1 CryptExportPublickKeyInfo OK.\n");
		} else {
			MyHandleError("1 CryptExportPublickKeyInfo failed.\n");
		}

		PBYTE pKey = new BYTE[dwLen];
		if (CryptExportPublicKeyInfo(hCryptProv, AT_KEYEXCHANGE, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, (PCERT_PUBLIC_KEY_INFO)pKey, &dwLen)) {
			MyHandleError("2 CryptExportPublickKeyInfo OK.\n");
		}
		else {
			MyHandleError("2 CryptExportPublickKeyInfo failed.\n");
		}
}
Offline Kirill Sobolev  
#4 Оставлено : 21 августа 2014 г. 14:03:07(UTC)
Кирилл Соболев

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

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

Поблагодарили: 177 раз в 168 постах
А в какой строке ошибка?
Если контейнер из предыдущего фрагмента, то
Код:
		if (CryptAcquireContext(
			&hCryptProv,        // Address for handle to be returned.
			NULL,               // Use the current user's logon name.
			NULL,               // Use the default provider.
			PROV_RSA_FULL,      // Need to both encrypt and sign.
			NULL))              // No flags needed.
		{
			printf("A cryptographic provider has been acquired. \n");
		}
		else
		{
			free(pbNameEncoded);
			MyHandleError("CryptAcquireContext failed. \n");
		}

работать не будет, вместо PROV_RSA_FULL нужно 75.
Техническую поддержку оказываем тут
Наша база знаний
thanks 1 пользователь поблагодарил Кирилл Соболев за этот пост.
manigu оставлено 21.08.2014(UTC)
Offline manigu  
#5 Оставлено : 21 августа 2014 г. 16:17:05(UTC)
manigu

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

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

Сказал(а) «Спасибо»: 21 раз
Автор: Kirill Sobolev Перейти к цитате
А в какой строке ошибка?
Если контейнер из предыдущего фрагмента, то
Код:
		if (CryptAcquireContext(
			&hCryptProv,        // Address for handle to be returned.
			NULL,               // Use the current user's logon name.
			NULL,               // Use the default provider.
			PROV_RSA_FULL,      // Need to both encrypt and sign.
			NULL))              // No flags needed.
		{
			printf("A cryptographic provider has been acquired. \n");
		}
		else
		{
			free(pbNameEncoded);
			MyHandleError("CryptAcquireContext failed. \n");
		}

работать не будет, вместо PROV_RSA_FULL нужно 75.


Кажется что я не то делаю...
Мне нужно сформировать ключ электронной подписи на носитель и к нему открытый ключ в виде файл запроса.
Также мне предоставили в качестве примера программу KeyFile bank, которая выполняет вышеописанное.

Принцип работы KeyFile bank: вбиваю данные -> биологический датчик просит потыкать на кнопки -> Для созданного контейнера просят задать пароль. На выходе созданный контейнер и файл запроса (%userName%.req) в указанной директории.

У меня всё тоже самое, только при создании сертификата просят указать пароль контейнера(в KeyFile bank, как то реализованно без этого).

поменял PROV_RSA_FULL на 75, теперь получаю ошибку "80090008" при вызове CryptSignAndEncodeCertificate Brick wall

createRequest определена в MakeContainer
Код:

void createRequest() {
		
		CERT_RDN_ATTR rgNameAttr[] = {
			"2.5.4.3",                             // pszObjId 
			CERT_RDN_PRINTABLE_STRING,             // dwValueType
			strlen(CERT_SUBJECT_NAME),             // value.cbData
			(BYTE*)CERT_SUBJECT_NAME };

		CERT_RDN rgRDN[] = {1, &rgNameAttr[0] };
		CERT_NAME_INFO Name = {1, rgRDN };

		CERT_REQUEST_INFO  CertReqInfo;
		CERT_NAME_BLOB  SubjNameBlob;
		DWORD  cbNameEncoded;
		BYTE*  pbNameEncoded;
		DWORD  cbPublicKeyInfo;
		CERT_PUBLIC_KEY_INFO*  pbPublicKeyInfo;
		DWORD  cbEncodedCertReqSize;
		CRYPT_OBJID_BLOB  Parameters;
		CRYPT_ALGORITHM_IDENTIFIER  SigAlg;
		BYTE*  pbSignedEncodedCertReq;
		char*  pSignedEncodedCertReqBlob;

		if (CryptEncodeObject(
			MY_ENCODING_TYPE,     // Encoding type
			X509_NAME,            // Structure type
			&Name,                // Address of CERT_NAME_INFO structure
			NULL,                 // pbEncoded
			&cbNameEncoded))      // pbEncoded size
		{
			printf("The first call to CryptEncodeObject succeeded. \n");
		}
		else
		{
			MyHandleError("The first call to CryptEncodeObject failed. \nA public/private key pair may not exit in the container. \n");
		}

		if (!(pbNameEncoded = (BYTE*)malloc(cbNameEncoded)))
			MyHandleError("The pbNamencoded malloc operation failed. \n");
		
		if (CryptEncodeObject(
			MY_ENCODING_TYPE,    // Encoding type
			X509_NAME,           // Structure type
			&Name,               // Address of CERT_NAME_INFO structure
			pbNameEncoded,       // pbEncoded
			&cbNameEncoded))     // pbEncoded size
		{
			printf("The object is encoded. \n");
		}
		else
		{
			free(pbNameEncoded);
			MyHandleError("The second call to CryptEncodeObject failed. \n");
		}

		SubjNameBlob.cbData = cbNameEncoded;
		SubjNameBlob.pbData = pbNameEncoded;
		CertReqInfo.Subject = SubjNameBlob;

		CertReqInfo.cAttribute = 0;
		CertReqInfo.rgAttribute = NULL;
		CertReqInfo.dwVersion = CERT_REQUEST_V1;

		
		if (CryptAcquireContext(
			&hCryptProv,        // Address for handle to be returned.
			UserName,               // Use the current user's logon name.
			ProviderName,               // Use the default provider.
			75,      // Need to both encrypt and sign.
			NULL))              // No flags needed.
		{
			printf("A cryptographic provider has been acquired. \n");
		}
		else
		{
			free(pbNameEncoded);
			MyHandleError("CryptAcquireContext failed. \n");
		}
		
		if (CryptExportPublicKeyInfo(
			hCryptProv,            // Provider handle
			AT_KEYEXCHANGE,          // Key spec
			MY_ENCODING_TYPE,      // Encoding type
			NULL,                  // pbPublicKeyInfo
			&cbPublicKeyInfo))     // Size of PublicKeyInfo
		{
			printf("The keyinfo structure is %d bytes. \n", cbPublicKeyInfo);
		}
		else
		{
			free(pbNameEncoded);
			MyHandleError("The first call to CryptExportPublickKeyInfo failed. \nThe probable cause is that \nthere is no key pair in the key container. \n");
		}

		if (pbPublicKeyInfo = (CERT_PUBLIC_KEY_INFO*)malloc(cbPublicKeyInfo))
		{
			printf("Memory is allocated for the public key structure. \n");
		}
		else
		{
			free(pbNameEncoded);
			MyHandleError("Memory allocation failed. \n");
		}

		if (CryptExportPublicKeyInfo(
			hCryptProv,            // Provider handle
			AT_KEYEXCHANGE,          // Key spec
			MY_ENCODING_TYPE,      // Encoding type
			pbPublicKeyInfo,       // pbPublicKeyInfo
			&cbPublicKeyInfo))     // Size of PublicKeyInfo
		{
			printf("The key has been exported. \n");
		}
		else
		{
			free(pbNameEncoded);
			free(pbPublicKeyInfo);
			MyHandleError("The second call to CryptExportPublicKeyInfo failed. \n");
		}

		CertReqInfo.SubjectPublicKeyInfo = *pbPublicKeyInfo;

		memset(&Parameters, 0, sizeof(Parameters));
		SigAlg.pszObjId = szOID_OIWSEC_sha1RSASign;
		SigAlg.Parameters = Parameters;

		if (CryptSignAndEncodeCertificate(
			hCryptProv,                      // Crypto provider
			AT_KEYEXCHANGE,                  // Key spec
			MY_ENCODING_TYPE,                // Encoding type
			X509_CERT_REQUEST_TO_BE_SIGNED,  // Structure type
			&CertReqInfo,                    // Structure information
			&SigAlg,                         // Signature algorithm
			NULL,                            // Not used
			NULL,                            // pbSignedEncodedCertReq
			&cbEncodedCertReqSize))          // Size of certificate 
			// required
		{
			printf("The size of the encoded certificate is set. \n");
		}
		else
		{
			free(pbNameEncoded);
			free(pbPublicKeyInfo);
			MyHandleError("First call to CryptSignandEncode failed. \n");
		}

		if (pbSignedEncodedCertReq = (BYTE*)malloc(cbEncodedCertReqSize))
		{
			printf("Memory has been allocated.\n");
		}
		else
		{
			free(pbNameEncoded);
			free(pbPublicKeyInfo);
			MyHandleError("The malloc operation failed. \n");
		}

		if (CryptSignAndEncodeCertificate(
			hCryptProv,                     // Crypto provider
			AT_KEYEXCHANGE,                 // Key spec
			MY_ENCODING_TYPE,               // Encoding type
			X509_CERT_REQUEST_TO_BE_SIGNED, // Struct type
			&CertReqInfo,                   // Struct info        
			&SigAlg,                        // Signature algorithm
			NULL,                           // Not used
			pbSignedEncodedCertReq,         // Pointer
			&cbEncodedCertReqSize))         // Length of the message
		{
			printf("The message is encoded and signed. \n");
		}
		else
		{
			free(pbNameEncoded);
			free(pbPublicKeyInfo);
			free(pbSignedEncodedCertReq);
			MyHandleError("The second call to CryptSignAndEncode failed. \n");
		}

		pSignedEncodedCertReqBlob = new char[(cbEncodedCertReqSize * 2) + 1];

		ByteToStr(cbEncodedCertReqSize, pbSignedEncodedCertReq, pSignedEncodedCertReqBlob);

		printf("The string created is: \n");
		printf("%s\n", pSignedEncodedCertReqBlob);

		free(pbNameEncoded);
		free(pbPublicKeyInfo);
		free(pbSignedEncodedCertReq);
		CryptReleaseContext(hCryptProv, 0);

		printf("\nMemory freed. Program ran without error. \n");
	}
Offline Kirill Sobolev  
#6 Оставлено : 21 августа 2014 г. 17:39:19(UTC)
Кирилл Соболев

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

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

Поблагодарили: 177 раз в 168 постах
Цитата:
У меня всё тоже самое, только при создании сертификата просят указать пароль контейнера(в KeyFile bank, как то реализованно без этого).

Вы второй раз вызываете CryptAcquireContext для создания запроса. Передавайте туда hCryptProv из CreateNewContainer.
Цитата:
поменял PROV_RSA_FULL на 75, теперь получаю ошибку "80090008" при вызове CryptSignAndEncodeCertificate Brick wall

Алгоритм хеширования в
Код:
SigAlg.pszObjId = szOID_OIWSEC_sha1RSASign;

тоже надо поменять на
Код:
#define szOID_CP_GOST_R3411 "1.2.643.2.2.9"


Техническую поддержку оказываем тут
Наша база знаний
thanks 1 пользователь поблагодарил Кирилл Соболев за этот пост.
manigu оставлено 22.08.2014(UTC)
Offline manigu  
#7 Оставлено : 22 августа 2014 г. 10:15:17(UTC)
manigu

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

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

Сказал(а) «Спасибо»: 21 раз
Спасибо Вам, очень помогли.
RSS Лента  Atom Лента
Пользователи, просматривающие эту тему
Guest
Быстрый переход  
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.