//---------------------------------------------------------------------------
//#include <vcl.h>
#include <windows.h>
#include <wincrypt.h>
#include <stdio.h>
#pragma hdrstop
#define CERT_SUBJECT_NAME "This certificate user"
#define CRYPT_MS_KEYSET         0x01000000
#define CRYPT_NEWKEYSETEX      (CRYPT_NEWKEYSET|CRYPT_MS_KEYSET)
#define KP_USER_KEY             67
#define MY_ENCODING_TYPE  (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
#define MS_ENROLL_CERTTYPE_EXTENSION      "1.3.6.1.4.1.311.20.2"
#define RSA_SIGN_OID  "1.2.840.113549.1.1.5"
#define GOST_SIGN_OID "1.3.6.1.4.1.6801.1.2.2"
#define GOST_HASH_OID "1.3.6.1.4.1.6801.1.2.1"
#define szOID_SUBJECT_X_NAME "1.3.6.1.4.1.6801.2.8"
#define RSA_HASH_OID  "1.2.840.113549.1.1.5"
//---------------------------------------------------------------------------

#pragma argsused
//-------------------------------------------------------------------
// This program uses the function ByteToStr to convert an array
// of BYTEs to a char string.

DWORD cms_size;
BYTE* cms=NULL;
BYTE*  pbSignedEncodedCertReq=NULL;
DWORD  cbEncodedCertReqSize;
int CreatePKCS10(DWORD provType, char* provName, char* profile, char* templ, long templ_size,char* key_usage,long key_usage_length, long oid_count,long key_type, long sizeKey);
int CreatePKCS7onProfile(DWORD provType, char* provName,char* profile);
int CreatePKCS7OnCertificate(wchar_t* DName,DWORD provType, char* provName);
int InstallCert(BYTE* pbuffer_api,unsigned long certSize, char* profile,DWORD provType, char* provName);
void ByteToStr(
     DWORD cb,
     void* pv,
     LPSTR sz)
//-------------------------------------------------------------------
// Parameters passed are:
//    pv is the array of BYTEs to be converted.
//    cb is the number of BYTEs in the array.
//    sz is a pointer to the string to be returned.

{
//-------------------------------------------------------------------
//  Declare and initialize local variables.

BYTE* pb = (BYTE*) pv; // local pointer to a BYTE in the BYTE array
DWORD i;               // local loop counter
int b;                 // local variable

//-------------------------------------------------------------------
//  Begin processing loop.

for (i = 0; i<cb; i++)
{
   b = (*pb & 0xF0) >> 4;
   *sz++ = (b <= 9) ? b + '0' : (b - 10) + 'A';
   b = *pb & 0x0F;
   *sz++ = (b <= 9) ? b + '0' : (b - 10) + 'A';
   pb++;
}
*sz++ = 0;
}

int main(int argc, char* argv[])
{

char profile[256];
char provName[128];
DWORD provType=25;  // тип криптопровайдера, 25 - ГОСТ, 1 - RSA
//String templ = "CN=RA_GOST,O=Template,C=KZ";   // шаблон для выпуска сертификата
char* templ = "CN=RA_GOST,O=Template,C=KZ";   // шаблон для выпуска сертификата
//String eku = "1.3.6.1.5.5.7.3.4"; // расширенное использование ключа
 char* eku =  "1.3.6.1.5.5.7.3.4"; // расширенное использование ключа
long sizeKey = 512;  // размер ключа
long key_type= AT_SIGNATURE;   // тип ключа
int ret = 0;
char profile_manager[256];
unsigned char* pbCert=NULL;
unsigned long certSize;

memset(profile,0,sizeof(profile));
sprintf(profile,"%s","profile://test");    // профайл, в котором будет сгенерирован ключ

memset(provName,0,sizeof(provName));
sprintf(provName,"%s","Tumar CSP");  // имя криптопровайдера, Tumar CSP - для ГОСТ, Tumar CSP RSA - для RSA

// создаем запрос на сертификат
ret = CreatePKCS10(provType,provName,profile,templ,strlen(templ),eku,strlen(eku),1,key_type,key_type);

memset(profile_manager,0,sizeof(profile_manager));
sprintf(profile,"%s","profile://manager");    // профайл, в котором хранятся ключи того, кто подписывает запрос на сертификат
//ret = CreatePKCS7onProfile(provType,provName,profile_manager);

// можно подписать запрос, используя ключи из хранилища
wchar_t* dname_w = L"Ефимов Стас";
 ret = CreatePKCS7OnCertificate(dname_w,provType,provName);

//........  тут следует отправка запроса на CERTEX .............
//... получение сертификата в буфер pbCert....///
// и установка сертификата в хранилище


ret = InstallCert(pbCert,certSize,profile,provType,provName);

return 0;
}

int CreatePKCS10(DWORD provType, char* provName, char* profile, char* templ, long templ_size,char* key_usage,long key_usage_length, long oid_count,long key_type, long sizeKey)
{
DWORD  cbNameEncoded;
BYTE*  pbNameEncoded=NULL;
CERT_REQUEST_INFO  CertReqInfo;
CERT_NAME_BLOB  SubjNameBlob;
HCRYPTPROV  hCryptProv=0;
DWORD  cbPublicKeyInfo;
CERT_PUBLIC_KEY_INFO*  pbPublicKeyInfo=NULL;
CRYPT_OBJID_BLOB  Parameters;
CRYPT_ALGORITHM_IDENTIFIER  SigAlg;
DWORD key_algid=0;
HCRYPTKEY hKey = 0;
CERT_EXTENSIONS certExtens;
CERT_EXTENSION certExten[2];
int ext_index;
CTL_USAGE EnhKey;
long temp_index=0;
LPSTR arr_oid[8];
char ts[34];
DWORD ret=0;
try
{
	try
	{	
		CERT_RDN_ATTR rgNameAttr[] = {"2.5.4.3", CERT_RDN_PRINTABLE_STRING, strlen(CERT_SUBJECT_NAME),(BYTE*)CERT_SUBJECT_NAME};            
		CERT_RDN rgRDN[] = {1,&rgNameAttr[0]};  
		CERT_NAME_INFO Name = {1,                 rgRDN};             
   
		switch(sizeKey)
		{
			case 512:
			if (key_type == AT_SIGNATURE)
			{
                key_algid = 0xaa3a;   // ГОСТ, на подпись
			}
			else
			{
                key_algid =0xa045;   // ГОСТ, на шифрование
			}
			break;                                  
        case 1024: key_algid = 0xa450; break; // RSA 1024
        case 1536: key_algid =0xa451; break;  // RSA 1536
        case 2048: key_algid = 0xa452; break;  // RSA 2048
        default:  if (key_type == AT_SIGNATURE)
                        {
                                key_algid = 0xaa3a;
                        }
                        else
                        {
                                key_algid =0xa045;
                        }
                        break;
		}
			if(!CryptAcquireContext(&hCryptProv, profile, provName, provType, CRYPT_NEWKEYSETEX)) throw GetLastError();  // создаем контекст криптопровайдера на необходимый профайл
			if(!CryptGenKey(hCryptProv, key_algid,CRYPT_EXPORTABLE, &hKey)) throw GetLastError();    // генерация ключа
			if (!(CryptSetKeyParam(hKey,KP_USER_KEY ,NULL,0)))  throw GetLastError();                // активация ключа, чтобы подпись создавалась именно на нем
			if(!CryptExportPublicKeyInfo(hCryptProv,key_type,MY_ENCODING_TYPE,NULL,&cbPublicKeyInfo)) throw GetLastError(); // экспортируем необходимую информацию о ключе для вставки в запрос
			pbPublicKeyInfo = (CERT_PUBLIC_KEY_INFO*)malloc(cbPublicKeyInfo); // выделяем память
			if(!pbPublicKeyInfo) throw NTE_NO_MEMORY;
			if(!CryptExportPublicKeyInfo(hCryptProv,key_type,MY_ENCODING_TYPE, pbPublicKeyInfo, &cbPublicKeyInfo))throw GetLastError();
			if(!CryptEncodeObject(MY_ENCODING_TYPE,X509_NAME,&Name,NULL,&cbNameEncoded)) throw GetLastError(); // кодируем DN-имя сертификата
			if(!(pbNameEncoded = (BYTE*)malloc(cbNameEncoded))) throw NTE_NO_MEMORY;
			if(!CryptEncodeObject(MY_ENCODING_TYPE,X509_NAME,&Name,pbNameEncoded,&cbNameEncoded)) throw GetLastError();
			SubjNameBlob.cbData = cbNameEncoded;
			SubjNameBlob.pbData = pbNameEncoded;
			CertReqInfo.Subject = SubjNameBlob;
			CertReqInfo.cAttribute = 0;
			CertReqInfo.rgAttribute = NULL;
			CertReqInfo.dwVersion = CERT_REQUEST_V1;
			CertReqInfo.SubjectPublicKeyInfo = *pbPublicKeyInfo; // вкладываем в запрос информацию об открытом ключе
			certExtens.rgExtension = certExten;  // добавляем расширения сертификата (пустые)
			certExtens.cExtension = 0;
			ext_index = 0;
			// кодируем расширения сертификата: шаблон сертификата и расширенное использование сертификата
			if (templ_size!=0)   // templates
			{
				// создаем расширение сертификата и заполняем его поля
				certExten[ext_index].pszObjId = MS_ENROLL_CERTTYPE_EXTENSION; // тип расширения - шаблон сертификата
				certExten[ext_index].fCritical=0;                             // не критичное
				certExten[ext_index].Value.cbData = templ_size;                // размер значения шаблона
				certExten[ext_index].Value.pbData = (PBYTE)malloc(templ_size);
				memcpy(certExten[ext_index].Value.pbData,templ,templ_size);    // задаем сам шаблон
				certExtens.cExtension++;  // расширений в запросе стало на одно больше
				ext_index++;
			}


			if (key_usage_length!=0) // Enhanced Key Usage
			{
				// разбираем строку с оидами расширенного использования ключа
				EnhKey.rgpszUsageIdentifier=NULL;
				temp_index=0;
				EnhKey.rgpszUsageIdentifier = new char*[oid_count];
				for(int i=0;i<oid_count;i++)
				{
						// для каждого оида выделяем память
						EnhKey.rgpszUsageIdentifier[i] = new char[64];
						memset(EnhKey.rgpszUsageIdentifier[i],0,64);
				}

				char* str_temp = strtok(key_usage,",");
				memcpy(EnhKey.rgpszUsageIdentifier[temp_index],str_temp, strlen(str_temp));
				for(;;)
				{
						str_temp = strtok(NULL, ",");
						if (str_temp == NULL) break;
						temp_index++;
						// копируем оид в расширение
						memcpy(EnhKey.rgpszUsageIdentifier[temp_index],str_temp, strlen(str_temp));
				}

				EnhKey.cUsageIdentifier=oid_count;
				certExten[ext_index].pszObjId = szOID_ENHANCED_KEY_USAGE; // тип расширения
				certExten[ext_index].fCritical=0;    // не критичное
				certExten[ext_index].Value.cbData = 2048;
				certExten[ext_index].Value.pbData = (PBYTE)malloc(2048);  // выделяем память под закодированное расширение

				if (!CryptEncodeObjectEx(1,X509_ENHANCED_KEY_USAGE,&EnhKey,CRYPT_ENCODE_ALLOC_FLAG,NULL,&certExten[ext_index].Value.pbData,&certExten[ext_index].Value.cbData)) throw GetLastError();
				certExtens.cExtension++;
				ext_index++;
			}
			CertReqInfo.cAttribute = 0;
			CertReqInfo.rgAttribute = NULL;
			if (ext_index!=0)
			{
				CertReqInfo.cAttribute = 1;
				CertReqInfo.rgAttribute=(PCRYPT_ATTRIBUTE)malloc(sizeof(CRYPT_ATTRIBUTE));
				CertReqInfo.rgAttribute->pszObjId =  szOID_CERT_EXTENSIONS;
				CertReqInfo.rgAttribute->cValue=1;
				CertReqInfo.rgAttribute->rgValue =(PCRYPT_ATTR_BLOB)malloc(sizeof(CRYPT_ATTR_BLOB));
				// кодируем все значения расширений в asn и добавляем их в запрос
				if (!CryptEncodeObjectEx(1, szOID_CERT_EXTENSIONS, &certExtens, CRYPT_ENCODE_ALLOC_FLAG, NULL, &CertReqInfo.rgAttribute[0].rgValue[0].pbData,&CertReqInfo.rgAttribute[0].rgValue[0].cbData)) throw GetLastError();
			}
			// заполняем тип подписи
			memset(&Parameters, 0, sizeof(Parameters));
			memset(&ts, 0, sizeof(ts));
			switch(provType)
			{
				case 25:   sprintf(ts,"%s",GOST_SIGN_OID); // для ГОСТ
						 break;
				default:   sprintf(ts,"%s",RSA_SIGN_OID);  // для RSA
						break;
			}
			SigAlg.pszObjId = ts;
			SigAlg.Parameters = Parameters;
			// кодируем сам запрос
			if ((!CryptSignAndEncodeCertificate(hCryptProv, key_type, MY_ENCODING_TYPE, X509_CERT_REQUEST_TO_BE_SIGNED, &CertReqInfo,&SigAlg, NULL, NULL, &cbEncodedCertReqSize)))
							throw GetLastError();
			pbSignedEncodedCertReq = (BYTE*)malloc(cbEncodedCertReqSize);
			if(!pbSignedEncodedCertReq) throw NTE_NO_MEMORY;
			if ((!CryptSignAndEncodeCertificate(hCryptProv, key_type, MY_ENCODING_TYPE, X509_CERT_REQUEST_TO_BE_SIGNED, &CertReqInfo,&SigAlg, NULL, pbSignedEncodedCertReq, &cbEncodedCertReqSize)))
							throw GetLastError();
			 // полученный запрос содержится в   pbSignedEncodedCertReq
	}
	catch(DWORD err)
	{
		ret  = err;
	}
	catch(int err)
	{
	   ret =  err;
	}
	catch(...)
	{
	ret = 300;
	}
}
__finally
{
        if (pbNameEncoded) free(pbNameEncoded);
        if (pbPublicKeyInfo) free(pbPublicKeyInfo);
        if (pbSignedEncodedCertReq) free(pbSignedEncodedCertReq);
        if(hKey!=0) CryptDestroyKey(hKey);
        if(hCryptProv!=0) CryptReleaseContext(hCryptProv,0);
}
return ret;
}

int CreatePKCS7onProfile(DWORD provType, char* provName,char* profile)
{
DWORD ret=0;
HCRYPTPROV hCryptProv=0;
HCRYPTKEY phKey=0;
HCRYPTMSG hMsg=NULL;
PCCERT_CONTEXT pSignerCert=NULL;
FILETIME   fileTime;
SYSTEMTIME systemTime;
LPBYTE pbTime = NULL;
DWORD  cbTime = 0;
CRYPT_ATTR_BLOB cablob[1];
CRYPT_ATTRIBUTE ca[2];
CMSG_SIGNER_ENCODE_INFO SignerEncodeInfo;
CMSG_SIGNER_ENCODE_INFO SignerEncodeInfoArray[1];
CERT_BLOB SignerCertBlob;
CMSG_SIGNED_ENCODE_INFO SignedMsgEncodeInfo;
CERT_BLOB SignerCertBlobArray[1];
unsigned char* pbCertEncoded = NULL;
unsigned long cbCertEncoded=0;
char sn_hex[65];
DWORD code=0;
DWORD cms_size=0;
CRYPT_SIGN_MESSAGE_PARA  SigParams;
try
{
	try
	{

			 if(!CryptAcquireContext(&hCryptProv, profile, provName, provType, NULL)) throw GetLastError();  // создаем контекст криптопровайдера на необходимый профайл
			 if (!CryptGetUserKey(hCryptProv,AT_SIGNATURE,&phKey)) throw GetLastError();    // получаем контекст ключа, который необходимо использовать для подписи
			 if (!CryptGetKeyParam(phKey,KP_CERTIFICATE,NULL,&cbCertEncoded,0)) throw GetLastError(); // получаем сертификат подписывающего
			 pbCertEncoded = (unsigned char*)malloc(cbCertEncoded);
			if (pbCertEncoded==NULL) throw 300;
			if (!CryptGetKeyParam(phKey,KP_CERTIFICATE,pbCertEncoded,&cbCertEncoded,0)) throw GetLastError();
			pSignerCert = CertCreateCertificateContext(MY_ENCODING_TYPE, pbCertEncoded, cbCertEncoded);  // создаем контекст сертификата  для того, чтобы заполнить атрибуты сообщения
			if (pSignerCert==NULL) throw GetLastError();
			memset(&SignerEncodeInfo, 0, sizeof(CMSG_SIGNER_ENCODE_INFO));     // заполняем все необходимые атрибуты
			SignerEncodeInfo.cbSize = sizeof(CMSG_SIGNER_ENCODE_INFO);
			SignerEncodeInfo.pCertInfo = pSignerCert->pCertInfo;  // указываем сертификат подписавшего
			SignerEncodeInfo.hCryptProv = hCryptProv;
			SignerEncodeInfo.dwKeySpec = AT_SIGNATURE;
			memset(&SignerEncodeInfo.HashAlgorithm,0,sizeof(SignerEncodeInfo.HashAlgorithm));
			if (provType=25)
			{
					SignerEncodeInfo.HashAlgorithm.pszObjId = GOST_HASH_OID;
			}
			 else
			{
					SignerEncodeInfo.HashAlgorithm.pszObjId ="1.3.14.3.2.26";
			}
			SignerEncodeInfo.pvHashAuxInfo = NULL;
			GetSystemTime(&systemTime);
			SystemTimeToFileTime(&systemTime, &fileTime);
			code = CryptEncodeObject(MY_ENCODING_TYPE, szOID_RSA_signingTime, (LPVOID)&fileTime, NULL, &cbTime);    // кодируем   время подписания
			if (!code)  throw GetLastError();
			pbTime = (BYTE*)malloc(cbTime);
			memset(pbTime,0,cbTime);
			if (!pbTime) throw 300;
			code = CryptEncodeObject(MY_ENCODING_TYPE, szOID_RSA_signingTime, (LPVOID)&fileTime, pbTime, &cbTime);
			if (!code) throw GetLastError();
			cablob[0].cbData = cbTime;
			cablob[0].pbData = (BYTE*)malloc(cbTime);
			memcpy(cablob[0].pbData,pbTime,cbTime);
			ca[0].pszObjId = szOID_RSA_signingTime;
			ca[0].cValue = 1;
			ca[0].rgValue = cablob;
			CRYPT_ATTR_BLOB cablob2[1];
			cablob2[0].cbData = pSignerCert->pCertInfo->Subject.cbData;
			cablob2[0].pbData = (BYTE*)malloc(pSignerCert->pCertInfo->Subject.cbData);
			memcpy(cablob2[0].pbData,pSignerCert->pCertInfo->Subject.pbData,pSignerCert->pCertInfo->Subject.cbData);  // кодируем имя подписывающего
			ca[1].pszObjId = szOID_SUBJECT_X_NAME;
			ca[1].cValue = 1;
			ca[1].rgValue = cablob2;
			if (strstr(pSignerCert->pCertInfo->SignatureAlgorithm.pszObjId,"1.3.6.1.4.1.6801")!=NULL)  // присоединяем атрибуты к сообщению
			{
					SignerEncodeInfo.cAuthAttr=2;
					SignerEncodeInfo.rgAuthAttr = ca;
			}
			else
			{
					SigParams.cUnauthAttr=2;
					SigParams.rgUnauthAttr = ca;
			}
			SignerEncodeInfoArray[0] = SignerEncodeInfo;
			SignerCertBlob.cbData = pSignerCert->cbCertEncoded;    // добавляем сертификат подписавшего 
			SignerCertBlob.pbData = pSignerCert->pbCertEncoded;
			SignerCertBlobArray[0] = SignerCertBlob;
			memset(&SignedMsgEncodeInfo, 0, sizeof(CMSG_SIGNED_ENCODE_INFO));
			SignedMsgEncodeInfo.cbSize = sizeof(CMSG_SIGNED_ENCODE_INFO);
			SignedMsgEncodeInfo.cSigners = 1;   // количество подписывающих
			SignedMsgEncodeInfo.rgSigners = SignerEncodeInfoArray;
			SignedMsgEncodeInfo.cCertEncoded = 1;  // количество сертификатов в сообщении
			SignedMsgEncodeInfo.rgCertEncoded = SignerCertBlobArray;
			SignedMsgEncodeInfo.rgCrlEncoded = NULL; // количество CRL в сообщении
			// вычисляем размер буфера необходимого для сохранения подписываемого сообщения
			cms_size = CryptMsgCalculateEncodedLength(MY_ENCODING_TYPE,0,CMSG_SIGNED,&SignedMsgEncodeInfo,NULL,cbEncodedCertReqSize);
			cms = (BYTE *) malloc(cms_size);
			hMsg = CryptMsgOpenToEncode(MY_ENCODING_TYPE,0,CMSG_SIGNED,&SignedMsgEncodeInfo,NULL,NULL);
			if (hMsg==NULL) throw GetLastError();
			// добавляем подписываемый контент
			if(!CryptMsgUpdate(hMsg,pbSignedEncodedCertReq,cbEncodedCertReqSize,TRUE)) throw GetLastError();
			// получаем подписанное сообщение
			if(!CryptMsgGetParam(hMsg,CMSG_CONTENT_PARAM,0,cms,&cms_size)) throw GetLastError();
			if (!CryptMsgClose(hMsg)) throw GetLastError();
			ret=0;
	}
	catch(DWORD err)
	{
	ret= err;
	}
	catch(int err)
	{
	ret=err;
	}
	catch(...)
	{
	ret =300;
	}
}
__finally
{
        if (phKey) CryptDestroyKey(phKey);
        if (hCryptProv) CryptReleaseContext(hCryptProv,0);
        if (pSignerCert) CertFreeCertificateContext(pSignerCert);
        if (pbCertEncoded) free(pbCertEncoded);
        if (pbTime) free(pbTime);
}
return ret;
}
int CreatePKCS7OnCertificate(wchar_t*DName,DWORD provType, char* provName)
{
DWORD ret=0;
HCERTSTORE hStoreHandle=NULL;
PCCERT_CONTEXT pSignerCert=NULL;
CRYPT_SIGN_MESSAGE_PARA  SigParams;
FILETIME   fileTime;
SYSTEMTIME systemTime;
DWORD code=0;
CRYPT_ATTR_BLOB cablob[1];
CRYPT_ATTRIBUTE ca[2];
LPBYTE pbTime = NULL;
DWORD  cbTime = 0;
char ht[32];
const BYTE* MessageArray[] = {pbSignedEncodedCertReq};
DWORD MessageSizeArray[1];
MessageSizeArray[0] = cbEncodedCertReqSize;
try
{
	try
	{
		   // открываем хранилище
		   hStoreHandle = CertOpenSystemStore(0,"MY");
		   // находим в хранилище сертификат подписывающего
		   pSignerCert = CertFindCertificateInStore(hStoreHandle,MY_ENCODING_TYPE,0,CERT_FIND_SUBJECT_STR,DName,NULL);
		   if (pSignerCert==NULL) throw GetLastError();
	       
		   memset(&SigParams,0,sizeof(CRYPT_SIGN_MESSAGE_PARA));
		   SigParams.cbSize = sizeof(CRYPT_SIGN_MESSAGE_PARA);
		   SigParams.dwMsgEncodingType = MY_ENCODING_TYPE;
		   SigParams.pSigningCert = pSignerCert;  // указываем сертификат подписывающего

		   GetSystemTime(&systemTime);
		   SystemTimeToFileTime(&systemTime, &fileTime);
		   code = CryptEncodeObject(MY_ENCODING_TYPE, szOID_RSA_signingTime, (LPVOID)&fileTime, NULL, &cbTime);   // кодируем время подписи
		   if (!code)  throw GetLastError();
		   pbTime = (BYTE*) calloc(cbTime,sizeof(BYTE));
		   if (!pbTime) throw 300;
		   code = CryptEncodeObject(MY_ENCODING_TYPE, szOID_RSA_signingTime, (LPVOID)&fileTime, pbTime, &cbTime);
		   if (!code) throw GetLastError();

		   // добавляем время подписи в атрибуты сообщение
		   cablob[0].cbData = cbTime;
		   cablob[0].pbData = pbTime;
		   ca[0].pszObjId = szOID_RSA_signingTime;
		   ca[0].cValue = 1;
		   ca[0].rgValue = cablob;


		   CRYPT_ATTR_BLOB cablob2[1];
		   cablob2[0].cbData = pSignerCert->pCertInfo->Subject.cbData;   // добавляем имя подписавшего
		   cablob2[0].pbData = pSignerCert->pCertInfo->Subject.pbData;
		   ca[1].pszObjId = szOID_SUBJECT_X_NAME;
		   ca[1].cValue = 1;
		   ca[1].rgValue = cablob2;

		   if (strstr(pSignerCert->pCertInfo->SignatureAlgorithm.pszObjId,"1.3.6.1.4.1.6801")!=NULL)    // добавляем атрибуты в сообщение
		   {
					SigParams.cAuthAttr = 2;
					SigParams.rgAuthAttr = ca;
		   }
		   else
		   {
					SigParams.cUnauthAttr=2;
					SigParams.rgUnauthAttr = ca;
		   }

		   memset(&ht,0,sizeof(ht));
	                                
		   if (strstr(pSignerCert->pCertInfo->SignatureAlgorithm.pszObjId,"1.3.6.1.4.1.6801")!=NULL)
		   {  SigParams.HashAlgorithm.pszObjId=GOST_HASH_OID;}
		   else
		   { SigParams.HashAlgorithm.pszObjId=RSA_HASH_OID; }

		   SigParams.cMsgCert = 1;             // количество сертификатов в сообщении
		   SigParams.rgpMsgCert = &pSignerCert;  // добавляем сертификат подписавшего
		   SigParams.dwInnerContentType = 0;
		   SigParams.cMsgCrl = 0;          // СОС в соообщении
		   SigParams.rgpMsgCrl=NULL;
		   SigParams.dwFlags = 0;
		   SigParams.pvHashAuxInfo = NULL;
		   cms=0;
		   // подписываем сообщение
		   if (!(CryptSignMessage(&SigParams,FALSE,1,MessageArray,MessageSizeArray,NULL,&cms_size))) throw GetLastError();
		   if(!(cms =(BYTE*)malloc(cms_size))) throw NTE_NO_MEMORY;
		   if (!(CryptSignMessage(&SigParams,FALSE,1,MessageArray,MessageSizeArray,cms,&cms_size))) throw GetLastError();

	}
	catch(DWORD err)
	{
	}
	catch(int err)
	{
	}
	catch(...)
	{
	}
}
__finally
{
	if (pSignerCert) CertFreeCertificateContext(pSignerCert);
        if (hStoreHandle) CertCloseStore(hStoreHandle,0);
}
return ret;
}

int InstallCert(BYTE* pbuffer_api,unsigned long certSize, char* profile,DWORD provType, char* provName)
{
DWORD ret=0;
HCRYPTPROV hCryptProv=0;
HCRYPTKEY  phUserKey=0;
HCERTSTORE  hStoreCert=0;
PCCERT_CONTEXT pCertContext=NULL;
try
{
	try
	{
		if(!CryptAcquireContext(&hCryptProv, profile, provName, provType,0)) throw GetLastError();  // создаем контекст криптопровайдера на необходимый профайл
		if (!CryptGetUserKey(hCryptProv,AT_SIGNATURE,&phUserKey)) throw GetLastError(); // получаем контекст ключа
                hStoreCert = CryptGetMessageCertificates(MY_ENCODING_TYPE,0,  CERT_SYSTEM_STORE_CURRENT_USER, pbuffer_api, certSize); // если ответ пришел в виде PKCS7
                if (hStoreCert!=NULL)
                {
                        if(!(pCertContext = CertFindCertificateInStore(hStoreCert,X509_ASN_ENCODING,0,CERT_FIND_ANY,NULL,NULL))) throw GetLastError();  //извлекаем оттуда сертификат
                        if (!(CryptSetKeyParam(phUserKey,KP_CERTIFICATE,pCertContext->pbCertEncoded,0)))throw GetLastError(); // и устанавливаем в контейнер
                }
                else // ответ - буфер с сертификатом
                {
		        if (!(CryptSetKeyParam(phUserKey,KP_CERTIFICATE,pbuffer_api,0)))throw GetLastError();   // устанавливаем сертификат в контейнер
                }
		ret=0;
	}
	catch(DWORD err)
	{
		ret=err;
	}
	catch(int err)
	{
		ret=err;
	}
	catch(...)
	{
		ret=300;
	}
}
__finally
{
 if (pCertContext) CertFreeCertificateContext(pCertContext);
 if (hStoreCert) CertCloseStore(hStoreCert,0);
 if (phUserKey) CryptDestroyKey(phUserKey);
 if (hCryptProv) CryptReleaseContext(hCryptProv,0);

}
return ret;
}

 
