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

Уведомление

Icon
Error

Опции
К последнему сообщению К первому непрочитанному
Offline dzhukov  
#1 Оставлено : 8 декабря 2017 г. 13:08:19(UTC)
dzhukov

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

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

Сказал(а) «Спасибо»: 3 раз
(*) есть связь с другой темой где помогли решить задачу,
теперь задача стала конкретней ссылка
Ранее получилось согласно [ CSP 4.0 R3 ]
получить ключевой контейнер
при помощи [ CryptAcquireCertificatePrivateKey() ]


появилась необходимость использовать именно [ CertGetCertificateContextProperty() ]
для получения [ HCRYPTPROV ]

т.к
"Мы обязаны использовать те ограничения, которые описаны в документе
для сертифицированной, закупленной версии криптопро."
а у нас [ CSP (Type:80) v4.0.9006 KC2 Release Ver:4.0.9708 ]
соответственно используем [ CryptSignHash ] из [ КриптоПро CSP 4.0 R2 ]

- CryptSignHash:
Разрешено использование только с ключевыми контейнерами, полученными ранее с помощью
вызова CertGetCertificateContextProperty из сертификата, проверенного с помощью
функции CertVerifyCertificateChainPolicy

- в sdk и в интернете не могу найти подходящего примера
для выполнения требования в документации
- плииииииз хееелп


заменяю этот кусочек:

Код:
 
        if(!CryptAcquireCertificatePrivateKey(
            pCertContext,
            0,
            NULL,
            &hProvSender,
            &dwKeySpecSender,
            NULL))
        {
            printf("JNI: Error during CryptAcquireCertificatePrivateKey. [%d]\n", GetLastErrorLocal());
        }



на такой кусочек

Код:
        
          if(!CertGetCertificateContextProperty(
                pCertContext,
                CERT_KEY_PROV_HANDLE_PROP_ID,
                &hProvSender,
                &cbData))
           {
               printf("JNI: Error during CertGetCertificateContextProperty. [%d]\n", GetLastErrorLocal());
           }


но вылетает ошибка [0x80092004]

я так понимаю этот ключик не поддерживается [ CERT_KEY_PROV_HANDLE_PROP_ID ]
как мне достать [ HCRYPTPROV (*)hProvSender] подскажите плииииииииз

Отредактировано пользователем 8 декабря 2017 г. 16:06:28(UTC)  | Причина: Не указана

Offline dzhukov  
#2 Оставлено : 8 декабря 2017 г. 14:18:26(UTC)
dzhukov

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

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

Сказал(а) «Спасибо»: 3 раз
можно ли получить какое - либо официальное подтверждение,
что можно использовать ф-ию [ CryptSignHash ]
согласно расширенному описанию в [ КриптоПро CSP 4.0 R3 (несертифицированный) ] (*) Правила пользования
(*) Разрешено использование только с ключевыми контейнерами, полученными ранее с помощью вызова CryptAcquireCertificatePrivateKey ...
с версией: [ CSP (Type:80) v4.0.9006 KC2 Release Ver:4.0.9708 ] ?

поиск примера по msdn, и по скаченному SDK
- показывает что там используется [ CryptSignHash ] согласно
описанию из [ КриптоПро CSP 4.0 R3 (несертифицированный) ]
(*) Разрешено использование только с ключевыми контейнерами, полученными ранее с помощью вызова CryptAcquireCertificatePrivateKey


как получить ключевой контейнер через [ CryptAcquireCertificatePrivateKey ] понятно и все, вроде, работает

как получить ключевой контейнер через [ CertGetCertificateContextProperty ] не понятно
(*) нужно т.к это документация на ф-ию [ CryptSignHash ] из [ КриптоПро CSP 4.0 R2 ] (*) Правила пользования

Offline dzhukov  
#3 Оставлено : 8 декабря 2017 г. 14:29:22(UTC)
dzhukov

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

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

Сказал(а) «Спасибо»: 3 раз
в документации на ф-ию [CertGetCertificateContextProperty] ссылка

Функция CertGetCertificateContextProperty получает информацию, содержащуюся в расширенных свойствах контекста сертификата.

Аналогична описанию в CryptoAPI. Поддерживаются только следующие параметры:
CERT_MD5_HASH_PROP_ID,
CERT_SHA1_HASH_PROP_ID,
CERT_SIGNATURE_HASH_PROP_ID,
CERT_KEY_IDENTIFIER_PROP_ID,
CERT_KEY_PROV_INFO_PROP_ID,
CERT_DESCRIPTION_PROP_ID,
CERT_ENHKEY_USAGE_PROP_ID,
CERT_FRIENDLY_NAME_PROP_ID


почитал про доступные ключи, запуск ф-ии ни с одним из этих ключей не может
помочь мне получить ключевой контейнер из сертификата

(*) есть ключик [ CERT_KEY_PROV_HANDLE_PROP_ID ]
Data type of pvData: A pointer to an HCRYPTPROV value.
Returns the provider handle obtained from CERT_KEY_CONTEXT_PROP_ID.

но он не поддерживается


помогите плииииз
Offline dzhukov  
#4 Оставлено : 8 декабря 2017 г. 15:32:00(UTC)
dzhukov

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

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

Сказал(а) «Спасибо»: 3 раз
ссылка на тему

olin:
Вышла промежуточная версия КриптоПро CSP 4.0 R3 (сборка 4.0.9914 Turing).
2017-06-30 КриптоПро CSP 4.0.9914 Turing

...
doc: CryptAcquireCertificatePrivateKey добавлен в комментарий к CryptSignHash (CPCSP-7503).
...

являлось ли изменение комментария старой версии необходимиым
именно из-за того, что это поставило в соответствие документацию
и реально демонстрируемые примеры использования?
Другими словами можно использовать
на старой сборке [ CSP (Type:80) v4.0.9006 KC2 Release Ver:4.0.9708 ]
согласно редактированию документации в версии [ КриптоПро CSP 4.0 R3 (сборка 4.0.9914 Turing) ]

Отредактировано пользователем 8 декабря 2017 г. 15:34:09(UTC)  | Причина: Не указана

Offline Русев Андрей  
#5 Оставлено : 8 декабря 2017 г. 17:02:52(UTC)
Русев Андрей

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

Группы: Администраторы, Участники
Зарегистрирован: 16.04.2008(UTC)
Сообщений: 1,271

Сказал(а) «Спасибо»: 22 раз
Поблагодарили: 446 раз в 325 постах
Если вам нужен CertGetCertificateContextProperty() вместо CryptAcquireCertificatePrivateKey(), используйте CERT_KEY_PROV_INFO_PROP_ID.
Официальная техподдержка. Официальная база знаний.
Offline dzhukov  
#6 Оставлено : 8 декабря 2017 г. 17:17:34(UTC)
dzhukov

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

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

Сказал(а) «Спасибо»: 3 раз
Автор: olin Перейти к цитате
Если вам нужен CertGetCertificateContextProperty() вместо CryptAcquireCertificatePrivateKey(), используйте CERT_KEY_PROV_INFO_PROP_ID.




(*) он вернет структуру в которой нет ссылки на ключевой контейнер
поэтому я не совсем что вы имеете ввиду
(*) возможно есть какой - то путь как получив вывод ф-ии [ CertGetCertificateContextProperty() ] с [ CERT_KEY_PROV_INFO_PROP_ID ]
можно получить ссылку на ключевой контейнер


CERT_KEY_PROV_INFO_PROP_ID
Data type of pvData: A pointer to a CRYPT_KEY_PROV_INFO structure.
Returns a pointer to a CRYPT_KEY_PROV_INFO structure.


просто я так понимаю документация говорит, что можно
получить ссылку на ключевой контейнер при помощи ф-ии [ CertGetCertificateContextProperty() ]

(*) CryptSignHash: (*) [ ЖТЯИ.00088-01 95 01. КриптоПро CSP. Правила пользования ]
Разрешено использование только с ключевыми контейнерами, полученными ранее с помощью
вызова CertGetCertificateContextProperty из сертификата, проверенного с помощью
функции CertVerifyCertificateChainPolicy

Отредактировано пользователем 8 декабря 2017 г. 17:27:56(UTC)  | Причина: Не указана

Offline Русев Андрей  
#7 Оставлено : 8 декабря 2017 г. 18:08:02(UTC)
Русев Андрей

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

Группы: Администраторы, Участники
Зарегистрирован: 16.04.2008(UTC)
Сообщений: 1,271

Сказал(а) «Спасибо»: 22 раз
Поблагодарили: 446 раз в 325 постах
Ссылка на закрытый ключ - это атрибут в хранилище, поэтому надо брать сертификат из хранилища, а не из файла.
Официальная техподдержка. Официальная база знаний.
Offline dzhukov  
#8 Оставлено : 8 декабря 2017 г. 19:00:15(UTC)
dzhukov

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

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

Сказал(а) «Спасибо»: 3 раз
Автор: olin Перейти к цитате
Ссылка на закрытый ключ - это атрибут в хранилище, поэтому надо брать сертификат из хранилища, а не из файла.


я чет не догоняю, прошу от вас терпения))))
вопрос же прямой : как получить ключевой контейнер вызовом ф-ии [ CertGetCertificateContextProperty ]?

(*) CryptSignHash: (*) [ ЖТЯИ.00088-01 95 01. КриптоПро CSP. Правила пользования ]
Разрешено использование только с ключевыми контейнерами, полученными ранее с помощью
вызова CertGetCertificateContextProperty из сертификата, проверенного с помощью
функции CertVerifyCertificateChainPolicy

вот текст документации который однозначно говорит,
что я ключевой контейнер должен получить вызовом [ CertGetCertificateContextProperty ]

(**) вопрос же именно в том, что как мне
написать код следуя документации если в ваших примерах вы этому требованию не следуете
- вы поэтому ведь документацию то и поправили в [ КриптоПро CSP 4.0 R3 (несертифицированный) ] )))?
- описав, что еще можно использовать [ CryptAcquireCertificatePrivateKey() ] вместе с [ CryptSignHash() ]

(***)
вы же видите, что используете ф-ию [ CryptSignHash ]
не с ключевыми контейнером полученными ранее с помощью вызова CertGetCertificateContextProperty из сертификата
(***)




(*) в этом и других файлах не нашел. sdk -> samples -> CSP -> SigningHash.c

Код:

...

int main(void)
{
    //-------------------------------------------------------------
    // Объявление и инициализация переменных.

    
    BYTE *pbBuffer= (BYTE *)"The data that is to be hashed and signed.";
    DWORD dwBufferLen = (DWORD)(strlen((char *)pbBuffer)+1);       
    DWORD dwSigLen;
    DWORD dwBlobLen;
    DWORD cbHash;
    FILE *signature;    

    // Получение дескриптора контекста криптографического провайдера.
    if(CryptAcquireContext(
	&hProv, 
	CONTAINER, 
	NULL, 
	PROV_GOST_2012_256, 
	0)) 
    {
	printf("CSP context acquired.\n");
    }
    else
    {
	HandleError("Error during CryptAcquireContext.");
    }
    //--------------------------------------------------------------------
    // Получение открытого ключа подписи. Этот открытый ключ будет 
    // использоваться получателем хеша для проверки подписи.
    // В случае, когда получатель имеет доступ к открытому ключю
    // отправителя с помощью сертификата, этот шаг не нужен.

    if(CryptGetUserKey(   
	hProv,    
	AT_SIGNATURE,    
	&hKey)) 
    {
	printf("The signature key has been acquired. \n");
    }
    else
    {
	HandleError("Error during CryptGetUserKey for signkey.");
    }
    //--------------------------------------------------------------------
    // Экпорт открытого ключа. Здесь открытый ключ экспортируется в 
    // PUBLICKEYBOLB для того, чтобы получатель подписанного хеша мог 
    // проверить подпись. Этот BLOB может быть записан в файл и передан
    // другому пользователю.

    if(CryptExportKey(   
	hKey,    
	0,    
	PUBLICKEYBLOB,
	0,    
	NULL, 
	&dwBlobLen)) 
    {
	printf("Size of the BLOB for the public key determined. \n");
    }
    else
    {
	HandleError("Error computing BLOB length.");
    }
    //--------------------------------------------------------------------
    // Распределение памяти под pbKeyBlob.

    pbKeyBlob = (BYTE*)malloc(dwBlobLen);
    if(!pbKeyBlob) 
	HandleError("Out of memory. \n");

    // Сам экспорт в ключевой BLOB.
    if(CryptExportKey(   
	hKey, 
	0,    
	PUBLICKEYBLOB,    
	0,    
	pbKeyBlob,    
	&dwBlobLen))
    {
	printf("Contents have been written to the BLOB. \n");
    }
    else
    {
	HandleError("Error during CryptExportKey.");
    }
    //--------------------------------------------------------------------
    // Создание объекта функции хеширования.

    if(CryptCreateHash(
	hProv, 
	CALG_GR3411_2012_256, 
	0, 
	0, 
	&hHash)) 
    {
	printf("Hash object created. \n");
    }
    else
    {
	HandleError("Error during CryptCreateHash.");
    }

    //--------------------------------------------------------------------
    // Передача параметра HP_OID объекта функции хеширования.
    //--------------------------------------------------------------------

    //--------------------------------------------------------------------
    // Определение размера BLOBа и распределение памяти.

    if(CryptGetHashParam(hHash,
	HP_OID,
	NULL,
	&cbHash,
	0))
    {
	printf("Size of the BLOB determined. \n");
    }
    else
    {
	HandleError("Error computing BLOB length.");
    }

    pbHash = (BYTE*)malloc(cbHash);
    if(!pbHash) 
	HandleError("Out of memory. \n");

    // Копирование параметра HP_OID в pbHash.
    if(CryptGetHashParam(hHash,
	HP_OID,
	pbHash,
	&cbHash,
	0))
    {
	printf("Parameters have been written to the pbHash. \n");
    }
    else
    {
	HandleError("Error during CryptGetHashParam.");
    }

    //--------------------------------------------------------------------
    // Вычисление криптографического хеша буфера.

    if(CryptHashData(
	hHash, 
	pbBuffer, 
	dwBufferLen, 
	0)) 
    {
	printf("The data buffer has been hashed.\n");
    }
    else
    {
	HandleError("Error during CryptHashData.");
    }

    // Определение размера подписи и распределение памяти.
    dwSigLen = 0;
    if(CryptSignHash(
	hHash, 
	AT_SIGNATURE, 
	NULL, 
	0, 
	NULL, 
	&dwSigLen)) 
    {
	printf("Signature length %d found.\n",dwSigLen);
    }
    else
    {
	HandleError("Error during CryptSignHash.");
    }

...

Отредактировано пользователем 8 декабря 2017 г. 19:26:13(UTC)  | Причина: Не указана

Offline dzhukov  
#9 Оставлено : 11 декабря 2017 г. 14:47:27(UTC)
dzhukov

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

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

Сказал(а) «Спасибо»: 3 раз
Похоже, произошло недопонимание.

Попробую переформулировать вопрос максимально четко и конкретно.

Изначальный код функции, реализующий подпись:

Код:

static HCRYPTPROV getSignContext(std::string name, std::string password)
{
	std::lock_guard<std::mutex> lock(exclusiveMutex);
	std::map<std::string, HCRYPTPROV>::iterator it = contextCache.find(name);
	if (it != contextCache.end())
	{
		HCRYPTPROV result = it->second;
		return result;
	}
	else
	{
		HCRYPTPROV hProv = 0;
		if (!CryptAcquireContext(
			&hProv,
			name.c_str(),
			NULL,
			PROV_GOST_2001_DH,
			0)){
			printf("JNI: getSignContext break on CryptAcquireContext [%d] for [%s]\n", GetLastErrorLocal(), name.c_str());
			return 0;
		}
		if (!CryptSetProvParam(hProv, PP_SIGNATURE_PIN, (BYTE*)password.c_str(), 0)){
			printf("JNI: do_low_sign_hash break on CryptSetProvParam [%d]\n", GetLastErrorLocal());
			//		cleanUp(hHash, data);
			return 0;
		}
		contextCache[name] = hProv;
		return hProv;
	}
}


BOOL do_low_sign_hash(BYTE * pbContent, DWORD cbContent, std::string certName, std::string password, BYTE_ARRAY * result)
{
	HCRYPTHASH hHash = 0;
	BYTE_ARRAY data = { pbContent, cbContent };
	DWORD keySpec = AT_KEYEXCHANGE;
	lanit::shared_lock_guard<lanit::shared_mutex> lock(rwMutex);


	HCRYPTPROV hProv;
	try {
		hProv = getSignContext(certName, password);
		if (!hProv){
			printf("JNI: do_low_sign_hash break on acquiring signing context \n");
			cleanUp(hHash, data);
			return 0;
		}

		if (!CryptCreateHash(hProv, CALG_GR3411, 0, 0, &hHash)){
			printf("JNI: do_low_sign_hash break on CryptCreateHash [%d]\n", GetLastErrorLocal());
			cleanUp(hHash, data, hProv);
			return 0;
		}
		if (!CryptSetHashParam(hHash, HP_OID, (BYTE*)OID_HashVerbaO, 0)){
			printf("JNI: do_low_sign_hash break on CryptSetHashParam [%d]\n", GetLastErrorLocal());
			cleanUp(hHash, data, hProv);
			return 0;
		}
		if (!CryptHashData(hHash, pbContent, cbContent, 0)){
			printf("JNI: do_low_sign_hash break on CryptHashData [%d]\n", GetLastErrorLocal());
			cleanUp(hHash, data, hProv);
			return 0;
		}

		result->size = 0;
		if (!CryptSignHash(hHash, keySpec, NULL, 0, NULL, &(result->size))){
			flipKeySpec(keySpec);
			if (!CryptSignHash(hHash, keySpec, NULL, 0, NULL, &(result->size))){
				printf("JNI: do_low_sign_hash break on CryptSignHash [%d]\n", GetLastErrorLocal());
				cleanUp(hHash, data, hProv);
				return 0;
			}
		}
		result->blob = new BYTE[result->size];
		BOOL isSuccessful = 1;
		if (!CryptSignHash(hHash, keySpec, NULL, 0, result->blob, &result->size)){
			isSuccessful = 0;
			printf("JNI: do_low_sign_hash break on CryptSignHash final [%d]\n", GetLastErrorLocal());
		}
		CryptDestroyHash(hHash);
		//CryptReleaseContext(hProv, 0);
		return isSuccessful;
	} catch (std::exception *e) {
		printf((*e).what());
		cleanUp(hHash, data, hProv);
		return 0;
	}
}



В нашем случае есть строгое ограничение использования именно сертифицированной версией CSP RC2 и нет возможности руководствоваться требованиями из несертифицированной CSP RC3.

Ограничения на использование функцииии CryptSignHash() из документации RC2:
"Разрешено использование только с ключевыми контейнерами, полученными ранее с помощью вызова CertGetCertificateContextProperty из сертификата, проверенного с помощью
функции CertVerifyCertificateChainPolicy"


Как мы понимаем, для выполнения требований из документации [RC2] необходимо:
1) получить ключевой контейнер при помощи функции CertGetCertificateContextProperty из сертификата
2) сертификат должен быть проверен с помощью функции CertVerifyCertificateChainPolicy
(*) с выполнением первого пункта проблема, нет понимания, как его выполнить.

Ниже реализация, которая на первый взгляд соответствует документации [RC2], однако она не работает, так как в функции [CertGetCertificateContextProperty]
не поддерживается работа с параметром [CERT_KEY_PROV_HANDLE_PROP_ID]

Код:

BOOL verifyCertificateChain(PCCERT_CONTEXT pCertContext)
{ ... в реализации этой ф-ии все понятно...}

static HCRYPTPROV getSignContext2(std::string name, std::string password)
{
	std::lock_guard<std::mutex> lock(exclusiveMutex);
	std::map<std::string, HCRYPTPROV>::iterator it = contextCache.find(name);

    LPCSTR lpszCertSubject = (LPCSTR) name.c_str();
    LPCSTR sPassword = (LPCSTR) password.c_str();
    HCERTSTORE hStoreHandle = 0;         // Äåñêðèïòîð õðàíèëèùà ñåðòèôèêàòîâ
    PCCERT_CONTEXT pCertSender = NULL;   // Êîíòåêñò ñåðòèôèêàòà îòïðàâèòåëÿ
    HCRYPTPROV hProvSender = 0;          // Äåñêðèïòîð CSP îòïðàâèòåëÿ
    DWORD dwKeySpecSender;

    // ---
    char pszNameString[256];
    PCCERT_CONTEXT  pCertContext = NULL; 
    PCRYPT_KEY_PROV_INFO pData;
    DWORD            cbData;

    DWORD            dwPropId = 0;
    void*            pvData;
    CRYPT_KEY_PROV_INFO *pCryptKeyProvInfo;
    DWORD cbName;
    DWORD dwKeySpec;

    HCRYPTPROV hCryptProv;         // CSP handle
    CHAR pszName[1000];
    pszName[0] = 0;

    const char * stores[] = { "My" , "uMy" , "mMy", "Root" , "uRoot" , "mRoot" , "CA" , "mCA" , "uCA" , "AddressBook" , "uAddressBook" , "mAddressBook" , "SPC" , "uSPC" , "mSPC" };
    DWORD cStores = 15;

    printf("JNI: start function getSignContext2  name: %s password: %s\n", lpszCertSubject, sPassword);


	if (it != contextCache.end())
	{
		HCRYPTPROV result = it->second;
		printf("JNI: Get store handle. from [contextCache]\n");
		return result;
	}
	else
	{

        //--------------------------------------------------------------------

        for (DWORD i = 0; i < cStores; i++) {

            printf("JNI: try find any certificate in [%s], use [CertOpenSystemStore] \n", stores[i]);

            hStoreHandle = CertOpenSystemStore(0, stores[i]);

            if(!hStoreHandle)
            {
                printf("JNI: Error getting store handle. [%d]\n", GetLastErrorLocal());
                continue;
            } else {
        	      printf("JNI: getting store handle from: [%s]\n", stores[i]);
            }

            // Find the certificates in the system store. 
            while(pCertContext = CertEnumCertificatesInStore(hStoreHandle, pCertContext))  
            {

                // find criptoProvider
                if(!( CryptAcquireCertificatePrivateKey(
                    pCertContext,
                    0,
                    NULL,
                    &hCryptProv,
                    &dwKeySpec,
                    NULL)))
                {
                    printf("CryptAcquireCertificatePrivateKey.\n");
                }

                cbName = 1000;
                // Read the name of the key container.
                if(CryptGetProvParam(
                    hCryptProv,
                    PP_CONTAINER,
                    (BYTE*)pszName,
                    &cbName,
                    0))
                {
                    printf("CryptGetProvParam succeeded.\n");
                    printf("Key Container name: %s\n", pszName);

                        // string compare 
                        if ( !strcmp( lpszCertSubject , pszName ) ) {
                            // printf("find is Successful ! \n");
                            break;
                        }
             
                } else {
                    printf("Error reading key container name.\n");
                }

            } // end [ while(pCertContext = ... ]

            // string compare 
            if ( !strcmp( lpszCertSubject , pszName ) ) {
                printf("find is Successful ! \n");
                break;
            }

        } // end [ for (DWORD ... ]

        //--------------------------------------------------------------------

	    if (!verifyCertificateChain(pCertContext)){
	        throw "error verifyCertificateChain";
	    }

        //--------------------------------------------------------------------

        if(!CertGetCertificateContextProperty(
                pCertContext,
                CERT_KEY_PROV_HANDLE_PROP_ID,
                &hProvSender,
                &cbData))
           {
               printf("JNI: Error during CertGetCertificateContextProperty. [%d]\n", GetLastErrorLocal());
           }


        if (!CryptSetProvParam(hProvSender, PP_SIGNATURE_PIN, (BYTE*)sPassword, 0)){
            throw "do_low_sign_hash break on CryptSetProvParam";
        }

	    contextCache[name] = hProvSender;


        // Clean up.
	    if(hStoreHandle)
	    {
	        CertCloseStore(hStoreHandle,0);
	    }

	    if(pCertSender)
        {
            CertFreeCertificateContext(pCertSender);
        }


	    return hProvSender;
	}
}


BOOL do_low_sign_hash(CERT_TYPE_PARAM &certTypeParam,BYTE * pbContent, DWORD cbContent, std::string certName, std::string password, BYTE_ARRAY * result)
{
	HCRYPTHASH hHash = 0;
	BYTE_ARRAY data = { pbContent, cbContent };
	DWORD keySpec = AT_KEYEXCHANGE;
	lanit::shared_lock_guard<lanit::shared_mutex> lock(rwMutex);


	HCRYPTPROV hProv;
	hProv = getSignContext2(certName, password);//getSignContext(certTypeParam.provType, certName, password);
	if (!hProv){
		throw "do_low_sign_hash break on acquiring signing context";
	}
	if (!CryptCreateHash(hProv, certTypeParam.algId, 0, 0, &hHash)){
		cleanUp(hHash, data, hProv);
		throw "do_low_sign_hash break on CryptCreateHash";
	}
	if(certTypeParam.algId == CALG_GR3411){
       	if (!CryptSetHashParam(hHash, HP_OID, (BYTE*)OID_HashVerbaO, 0)){
           	cleanUp(hHash, data, hProv);
           	throw "do_low_sign_hash break on CryptSetHashParam";
        }
    }
	if (!CryptHashData(hHash, pbContent, cbContent, 0)){
		cleanUp(hHash, data, hProv);
		throw ("do_low_sign_hash break on CryptHashData");
	}
	result->size = 0;
	if (!CryptSignHash(hHash, keySpec, NULL, 0, NULL, &(result->size))){
		flipKeySpec(keySpec);
		if (!CryptSignHash(hHash, keySpec, NULL, 0, NULL, &(result->size))){
			cleanUp(hHash, data, hProv);
			throw "do_low_sign_hash break on CryptSignHash";
		}
	}
	result->blob = new BYTE[result->size];
	BOOL isSuccessful = 1;
	if (!CryptSignHash(hHash, keySpec, NULL, 0, result->blob, &result->size)){
		isSuccessful = 0;
		throw "do_low_sign_hash break on CryptSignHash final";
	}
	CryptDestroyHash(hHash);
	//CryptReleaseContext(hProv, 0);
	char messStr[1000];
   	sprintf(messStr,"\nCertName[%s], (%d provtype), data[%s] sign hash is: \n",certName.c_str(),certTypeParam.provType,pbContent);
	printf(messStr);
	if(result->blob){
		int i,j,k;
		for(j = 0; j < result->size; j++) {
			printf("%02X", result->blob[j]);
		}
       	printf("\n");
       }
	return isSuccessful;
}


Выдержка из исправленной (более новой) документации несертифицированной версии CSP RC3, следовать которой мы не вправе:
"Разрешено использование только с ключевыми контейнерами, полученными ранее с помощью вызова CryptAcquireCertificatePrivateKey либо с помощью вызова CertGetCertificateContextProperty из сертификата, проверенного с помощью функции CertVerifyCertificateChainPolicy"

Для выполнения требований из документации [RC3] необходимо:
1) получить ключевой контейнер при помощи функции CertGetCertificateContextProperty из сертификата или с помощью вызова CryptAcquireCertificatePrivateKey.
2) сертификат должен быть проверен с помощью функции CertVerifyCertificateChainPolicy
В данном случае понятно, как выполнить требование: через [CryptAcquireCertificatePrivateKey], но при следовании документации [RC2] этот способ не является допустимым.

Код выполнения требований по документации [RC3]

Код:

BOOL verifyCertificateChain(PCCERT_CONTEXT pCertContext)
{ ... в реализации этой ф-ии все понятно...}

static HCRYPTPROV getSignContext2(std::string name, std::string password)
{
	std::lock_guard<std::mutex> lock(exclusiveMutex);
	std::map<std::string, HCRYPTPROV>::iterator it = contextCache.find(name);

    LPCSTR lpszCertSubject = (LPCSTR) name.c_str();
    LPCSTR sPassword = (LPCSTR) password.c_str();
    HCERTSTORE hStoreHandle = 0;         // 
    PCCERT_CONTEXT pCertSender = NULL;   // 
    HCRYPTPROV hProvSender = 0;          // 
    DWORD dwKeySpecSender;

    // ---
    char pszNameString[256];
    PCCERT_CONTEXT  pCertContext = NULL; 
    PCRYPT_KEY_PROV_INFO pData;
    DWORD            cbData;

    DWORD            dwPropId = 0;
    void*            pvData;
    CRYPT_KEY_PROV_INFO *pCryptKeyProvInfo;
    DWORD cbName;
    DWORD dwKeySpec;

    HCRYPTPROV hCryptProv;         // CSP handle
    CHAR pszName[1000];
    pszName[0] = 0;

    const char * stores[] = { "My" , "uMy" , "mMy", "Root" , "uRoot" , "mRoot" , "CA" , "mCA" , "uCA" , "AddressBook" , "uAddressBook" , "mAddressBook" , "SPC" , "uSPC" , "mSPC" };
    DWORD cStores = 15;

    printf("JNI: start function getSignContext2  name: %s password: %s\n", lpszCertSubject, sPassword);


	if (it != contextCache.end())
	{
		HCRYPTPROV result = it->second;
		printf("JNI: Get store handle. from [contextCache]\n");
		return result;
	}
	else
	{

        //--------------------------------------------------------------------

        for (DWORD i = 0; i < cStores; i++) {

            printf("JNI: try find any certificate in [%s], use [CertOpenSystemStore] \n", stores[i]);

            hStoreHandle = CertOpenSystemStore(0, stores[i]);

            if(!hStoreHandle)
            {
                printf("JNI: Error getting store handle. [%d]\n", GetLastErrorLocal());
                continue;
            } else {
        	      printf("JNI: getting store handle from: [%s]\n", stores[i]);
            }

            // Find the certificates in the system store. 
            while(pCertContext = CertEnumCertificatesInStore(hStoreHandle, pCertContext))  
            {

                // find criptoProvider
                if(!( CryptAcquireCertificatePrivateKey(
                    pCertContext,
                    0,
                    NULL,
                    &hCryptProv,
                    &dwKeySpec,
                    NULL)))
                {
                    printf("CryptAcquireCertificatePrivateKey.\n");
                }

                cbName = 1000;
                // Read the name of the key container.
                if(CryptGetProvParam(
                    hCryptProv,
                    PP_CONTAINER,
                    (BYTE*)pszName,
                    &cbName,
                    0))
                {
                    printf("CryptGetProvParam succeeded.\n");
                    printf("Key Container name: %s\n", pszName);

                        // string compare 
                        if ( !strcmp( lpszCertSubject , pszName ) ) {
                            // printf("find is Successful ! \n");
                            break;
                        }
             
                } else {
                    printf("Error reading key container name.\n");
                }

            } // end [ while(pCertContext = ... ]

            // string compare 
            if ( !strcmp( lpszCertSubject , pszName ) ) {
                printf("find is Successful ! \n");
                break;
            }

        } // end [ for (DWORD ... ]

      //--------------------------------------------------------------------

	    if (!verifyCertificateChain(pCertContext)){
	        printf("JNI: Error verifyCertificateChain [%d]\n", GetLastErrorLocal());
	        return 0;
	    }

        //--------------------------------------------------------------------

        if(!CryptAcquireCertificatePrivateKey(
            pCertContext,
            0,
            NULL,
            &hProvSender,
            &dwKeySpecSender,
            NULL))
        {
            printf("JNI: Error during CryptAcquireCertificatePrivateKey. [%d]\n", GetLastErrorLocal());
        }

        if (!CryptSetProvParam(hProvSender, PP_SIGNATURE_PIN, (BYTE*)sPassword, 0)){
            printf("JNI: do_low_sign_hash break on CryptSetProvParam [%d]\n", GetLastErrorLocal());
        	//		cleanUp(hHash, data);
        	return 0;
        }

	    contextCache[name] = hProvSender;


        // Clean up.
	    if(hStoreHandle)
	    {
	        CertCloseStore(hStoreHandle,0);
	    }

	    if(pCertSender)
        {
            CertFreeCertificateContext(pCertSender);
        }


	    return hProvSender;
	}
}


BOOL do_low_sign_hash(CERT_TYPE_PARAM &certTypeParam,BYTE * pbContent, DWORD cbContent, std::string certName, std::string password, BYTE_ARRAY * result)
{
	HCRYPTHASH hHash = 0;
	BYTE_ARRAY data = { pbContent, cbContent };
	DWORD keySpec = AT_KEYEXCHANGE;
	lanit::shared_lock_guard<lanit::shared_mutex> lock(rwMutex);


	HCRYPTPROV hProv;
	try {
		hProv = getSignContext2(certName, password);//getSignContext(certTypeParam.provType, certName, password);
		if (!hProv){
			printf("JNI: do_low_sign_hash break on acquiring signing context \n");
			//cleanUp(hHash, data);
			return 0;
		}

		if (!CryptCreateHash(hProv, CALG_GR3411, 0, 0, &hHash)){
			printf("JNI: do_low_sign_hash break on CryptCreateHash [%d]\n", GetLastErrorLocal());
			cleanUp(hHash, data, hProv);
			return 0;
		}
		if (!CryptSetHashParam(hHash, HP_OID, (BYTE*)OID_HashVerbaO, 0)){
			printf("JNI: do_low_sign_hash break on CryptSetHashParam [%d]\n", GetLastErrorLocal());
			cleanUp(hHash, data, hProv);
			return 0;
		}
		if (!CryptHashData(hHash, pbContent, cbContent, 0)){
			printf("JNI: do_low_sign_hash break on CryptHashData [%d]\n", GetLastErrorLocal());
			cleanUp(hHash, data, hProv);
			return 0;
		}

		result->size = 0;
		if (!CryptSignHash(hHash, keySpec, NULL, 0, NULL, &(result->size))){
			flipKeySpec(keySpec);
			if (!CryptSignHash(hHash, keySpec, NULL, 0, NULL, &(result->size))){
				printf("JNI: do_low_sign_hash break on CryptSignHash [%d]\n", GetLastErrorLocal());
				cleanUp(hHash, data, hProv);
				return 0;
			}
		}
		result->blob = new BYTE[result->size];
		BOOL isSuccessful = 1;
		if (!CryptSignHash(hHash, keySpec, NULL, 0, result->blob, &result->size)){
			isSuccessful = 0;
			printf("JNI: do_low_sign_hash break on CryptSignHash final [%d]\n", GetLastErrorLocal());
		}
		CryptDestroyHash(hHash);
		//CryptReleaseContext(hProv, 0);
		return isSuccessful;
	} catch (std::exception *e) {
		printf((*e).what());
		cleanUp(hHash, data, hProv);
		return 0;
	}
}




Просьба пояснить, как нужно написать код, ОСТАВАЯСЬ СТРОГО В РАМКАХ требований к использовании функции CryptSignHash из документации к CSP RC2?

Если это технически невозможно (например, в документации RC2 ошибка), какие существуют варианты ? Ведь проблема в том, что данный релиз - последний, сертифицированный на данный момент.

Отредактировано пользователем 11 декабря 2017 г. 18:14:15(UTC)  | Причина: Не указана

Offline Русев Андрей  
#10 Оставлено : 27 декабря 2017 г. 16:13:40(UTC)
Русев Андрей

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

Группы: Администраторы, Участники
Зарегистрирован: 16.04.2008(UTC)
Сообщений: 1,271

Сказал(а) «Спасибо»: 22 раз
Поблагодарили: 446 раз в 325 постах
Порядок такой:
  • сертификат для подписи должен быть в хранилище со ссылкой на закрытый ключ
  • берёте из хранилища этот сертификат
  • проверяете цепочку
  • CertGetCertificateContextProperty(CERT_KEY_PROV_INFO_PROP_ID) - в нём будет всё необходимое для
  • CryptAcquireContext
  • CryptSignHash
  • Официальная техподдержка. Официальная база знаний.
    RSS Лента  Atom Лента
    Пользователи, просматривающие эту тему
    Быстрый переход  
    Вы не можете создавать новые темы в этом форуме.
    Вы не можете отвечать в этом форуме.
    Вы не можете удалять Ваши сообщения в этом форуме.
    Вы не можете редактировать Ваши сообщения в этом форуме.
    Вы не можете создавать опросы в этом форуме.
    Вы не можете голосовать в этом форуме.