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

Уведомление

Icon
Error

Опции
К последнему сообщению К первому непрочитанному
Offline ekelhaft  
#1 Оставлено : 21 марта 2008 г. 13:54:21(UTC)
ekelhaft

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

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

Возникла проблема с CryptSignMessage. При вызове эта функция показывает окно ввода пина. Но, тк для того, чтобы создать подпись, ее надо вызывать дважды, окно для ввода пина тоже появляется дважды. Чтобы этого избежать, включаю кэширование: замечательно, окно ввода появляется один раз, потом появляться перестает. НО проблема в том, что при следующем подписывании мне нужно, чтобы оно опять появилось. Выключаю кэширование-- никакой реакции. Кэширование выключается только если я закрываю хранилище сертификатов, что мне делать каждый раз при попытке что-то подписать очень не хочется.

Если кто-нибудь поведает, как отключить кэширование или еще как-то сделать так, чтобы CryptSignMessage не просила пароль во время второго вызова, буду премного благодарна.
Вот код, натыренный из всяких примеров:
Код:

HCERTSTORE hStoreHandle;    
	if ( !( hStoreHandle = CertOpenStore(
    CERT_STORE_PROV_SYSTEM,
    0,
    NULL,
    CERT_SYSTEM_STORE_CURRENT_USER,
    L"MY")))
  {
    HandleError("Unable to open MY.");
  }

// Получаем указатель на сертификат

  PCCERT_CONTEXT pSignerCert; 

  if(pSignerCert = CertFindCertificateInStore(
    hStoreHandle,
    MY_TYPE,
    0,
    CERT_FIND_SUBJECT_STR,
    SIGNER_NAME,
    NULL))
  {
    printf("Cert found.\n");
  }
  else
  {
    HandleError( "Cert not found.");
  }
	


  BYTE  *pbSignedMessageBlob;
  DWORD cbSignedMessageBlob;

// Создаем и заполняем структуру для создания цифровой подписи
  CRYPT_SIGN_MESSAGE_PARA  SigParams;

  SigParams.cbSize = sizeof(CRYPT_SIGN_MESSAGE_PARA);
  SigParams.dwMsgEncodingType = MY_TYPE;
  SigParams.pSigningCert = pSignerCert;
  SigParams.HashAlgorithm.pszObjId = szOID_RSA_MD5;
  SigParams.HashAlgorithm.Parameters.cbData = NULL;
  SigParams.cMsgCert = 0;
  SigParams.rgpMsgCert = NULL;
  SigParams.cAuthAttr = 0;
  SigParams.dwInnerContentType = 0;
  SigParams.cMsgCrl = 0;
  SigParams.cUnauthAttr = 0;
  SigParams.dwFlags = 0;
  SigParams.pvHashAuxInfo = NULL;
  SigParams.rgAuthAttr = NULL;
  BYTE* pbMessage = (BYTE*)"ABCdef123";
  DWORD cbMessage = (DWORD)strlen((char*) pbMessage)+1;    
   const BYTE* MessageArray[] = {pbMessage};
  DWORD MessageSizeArray[1];
  MessageSizeArray[0] = cbMessage;

//Включаем кэширование

    DWORD cData;
    PCCERT_CONTEXT pCert= SigParams.pSigningCert;
    int ret = CertGetCertificateContextProperty(pCert, CERT_KEY_PROV_INFO_PROP_ID, NULL, &cData);
    CRYPT_KEY_PROV_INFO* pCryptKeyProvInfo  = NULL;
    if (ret) {
		pCryptKeyProvInfo = (CRYPT_KEY_PROV_INFO *)malloc(cData);
		if(!pCryptKeyProvInfo)
		HandleError("Error in allocation of memory.");

		ret = CertGetCertificateContextProperty(pCert,CERT_KEY_PROV_INFO_PROP_ID, pCryptKeyProvInfo,&cData);
		if (ret)
		{
			/* Установим флаг кеширования провайдера*/
			pCryptKeyProvInfo->dwFlags = CERT_SET_KEY_CONTEXT_PROP_ID;
			/* Установим свойства в контексте сертификата*/
			ret = CertSetCertificateContextProperty(pCert, CERT_KEY_PROV_INFO_PROP_ID,0, pCryptKeyProvInfo);

		}
	}




// Получаем длину буфера подписи. Тут появляется окно ввода пина

  if(CryptSignMessage(
    &SigParams,              // указатель на SigParams
    TRUE,                    // подпись создается отдельно 
    1,                       // число сообщений
    MessageArray,            // сообщение
    MessageSizeArray,        // длина сообщения
    NULL,                    // буфер для подписи
    &cbSignedMessageBlob))   // размер буфера
  {
    printf("Signature size %d.\n",cbSignedMessageBlob);
  }
  else
  {
    HandleError("Error in CryptSignMessage.");
  }

// выделяем память под подпись
  if(!(pbSignedMessageBlob = new BYTE[cbSignedMessageBlob]))
  {
    HandleError("Error in new[].");
  }

// формируем подпись. Окна ввода пина нет-- как надо. 
  if(CryptSignMessage(
    &SigParams,            // указатель на SigParams
    TRUE,                  // подпись создается отдельно 
    1,                     // число сообщений
    MessageArray,          // сообщение
    MessageSizeArray,      // длина сообщения
    pbSignedMessageBlob,   // буфер для подписи
    &cbSignedMessageBlob)) // размер буфера
  {
    printf("Signature: \n");
    print_signature(cbSignedMessageBlob, pbSignedMessageBlob);
  }
  else
  {
    HandleError("Errror in cryptsignmessage 2");
  }

 //выключаем кэширование

   ret = CertGetCertificateContextProperty(pCert, CERT_KEY_PROV_INFO_PROP_ID, NULL, &cData);
	if (ret) {
		if(pCryptKeyProvInfo)
			free(pCryptKeyProvInfo);
		pCryptKeyProvInfo = (CRYPT_KEY_PROV_INFO *)malloc(cData);
		if(!pCryptKeyProvInfo)
		HandleError("Error in allocation of memory.");

		ret = CertGetCertificateContextProperty(pCert,CERT_KEY_PROV_INFO_PROP_ID, pCryptKeyProvInfo,&cData);
		if (ret)
		{
			/* Убираем флаг кеширования провайдера*/
			pCryptKeyProvInfo->dwFlags = 0;
			/* Установим свойства в контексте сертификата*/
			ret = CertSetCertificateContextProperty(pCert, CERT_KEY_PROV_INFO_PROP_ID,0, pCryptKeyProvInfo);

		}
	}

//Подписываем второй раз. Тут должно появиться окно ввода пина. Ан нет.

  if(CryptSignMessage(
    &SigParams,              // указатель на SigParams
    TRUE,                    // подпись создается отдельно 
    1,                       // число сообщений
    MessageArray,            // сообщение
    MessageSizeArray,        // длина сообщения
    NULL,                    // буфер для подписи
    &cbSignedMessageBlob))   // размер буфера
  {
    printf("Signature size %d.\n",cbSignedMessageBlob);
  }
  else
  {
    HandleError("Error in CryptSignMessage.");
  }

	if(pbSignedMessageBlob)
		delete[] pbSignedMessageBlob;
  if(!(pbSignedMessageBlob = new BYTE[cbSignedMessageBlob]))
  {
    HandleError("Error in new[].");
  }

// формируем подпись
  if(CryptSignMessage(
    &SigParams,            // указатель на SigParams
    TRUE,                  // подпись создается отдельно 
    1,                     // число сообщений
    MessageArray,          // сообщение
    MessageSizeArray,      // длина сообщения
    pbSignedMessageBlob,   // буфер для подписи
    &cbSignedMessageBlob)) // размер буфера
  {
    printf("Signature: \n");
    print_signature(cbSignedMessageBlob, pbSignedMessageBlob);
  }
  else
  {
    HandleError("Errror in cryptsignmessage 2");
  }

Отредактировано пользователем 21 марта 2008 г. 13:55:45(UTC)  | Причина: Не указана

Offline Веревкин Сергей  
#2 Оставлено : 17 апреля 2008 г. 17:29:35(UTC)
Веревкин Сергей

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

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

Во-превых закрывать и открывать хранилище - ничего страшного вроде бы нет. Может попробовать pCert снова взять из хранилища?
Offline Serge3leo  
#3 Оставлено : 8 мая 2008 г. 9:13:57(UTC)
Serge3leo

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

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

Поблагодарили: 3 раз в 2 постах
ekelhaft написал:
Если кто-нибудь поведает, как отключить кэширование или еще как-то сделать так, чтобы CryptSignMessage не просила пароль во время второго вызова, буду премного благодарна.

Если мне не изменяет память, CERT_SET_KEY_PROV_HANDLE_PROP_ID побуждает CAPI оставлять контейнер открытым после выполнения "простых" функций работы с сообщениями. Сброс его не означает, что CAPI закроет и откроет контейнер перед проведением следующей операции. В лучшем случае, она его закроет после следующей операции.

Перечитайте ещё документацию "Handles to key providers that were kept open are automatically released when the store is closed."

Кроме этого метода кэширования, есть следующие:

1. Если процесс открыл контейнер и указал PIN-код/пароль, то до тех пор, пока он его не закрыл, он может открывать его без указания PIN-кода/пароля.

Т.е. если Вы сделаете CryptAcquireCertificatePrivateKey(), то ПИН/пароль будет кэшироваться, пока Вы его не освободите.

2. Процесс может сбросить кэш ПИН/пароль путём CryptSetProvParam(PP_EXCHANGE_PIN/PP_SIGNATURE_PIN...NULL).

Смотрите нашу документацию CSP_3_*.chm и документацию MS, например, The Smart Card Cryptographic Service Provider Cookbook


Отредактировано пользователем 8 мая 2008 г. 9:14:46(UTC)  | Причина: Не указана

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