// VerifySignDetachMessage.cpp : Defines the entry point for the console application.
//

#include <stdio.h>
#include <time.h>
#include <sys/stat.h>
#ifdef _WIN32
#include <windows.h>
#define strlib "..\\lib\\strlib.dll"
#else
#define GetProcAddress dlsym
#define FreeLibrary dlclose
#include <string>
#include  <unistd.h>
#include  <dlfcn.h>
#define strlib "../lib/libstr.so.1.0"
#define _cdecl
#define TRUE 1
#define FALSE 0

#endif
#ifndef _WIN32
typedef unsigned long DWORD;
typedef unsigned char BYTE;
typedef void *HINSTANCE;
typedef char CHAR;
#endif
#define CRYPT_VERIFYCONTEXT  0xF0000000
#define MORE_ONE_CA        0
#define MAX_BASE_DENCODED_SIZE(base_size)  (((base_size*3)/4)+4)
typedef unsigned long hCERTSTORE;
typedef unsigned long hCERTCONTEXT;
typedef unsigned long hCERTCOLLECTION;
typedef unsigned long hCRYPTMSG;
typedef unsigned long HCRYPTPROV;

typedef int(_cdecl *errorstring)(const int err);
typedef int(_cdecl *cspopencontext)(HCRYPTPROV *phProv,
	char *pszContainer,
	DWORD dwProvType,
	DWORD dwProvParam,
	DWORD dwFlags,
	BYTE * pbSignature,
	DWORD dwSigLen,
	BYTE * pbContainer,
	DWORD * dwContLen,
	HINSTANCE *phLib);
typedef int(_cdecl *crtopenstore)(DWORD StoreProvider,
	HCRYPTPROV hProv,
	unsigned long dwFlags,
	bool  bFlag,
	const void *pvParam,
	hCERTSTORE *phStore);
typedef int(_cdecl *setldapver) (hCERTSTORE hStore, int ver);
typedef int(_cdecl *crtsetstorepropertyext) (const hCERTSTORE hStore,
	const unsigned long Flags,
	const char *DName,
	const char *host,
	const char *port,
	const int timeOut,
	const char *name,
	const char *pass);
typedef int(_cdecl *getmycertificate)
(hCERTSTORE hStore,
	const char *DName,
	const unsigned long keySpec,
	const bool isCA,
	unsigned char *certBody,
	unsigned long *bodySize);
typedef int(_cdecl *getcertificatecontext)
(const hCERTSTORE hStore,
	const unsigned char *certBody,
	const unsigned long bodySize,
	hCERTCONTEXT *phContext);
typedef int(_cdecl *getcertsubjectkey)
(const hCERTSTORE hStore,
	const unsigned char *certBody,
	const unsigned long bodySize,
	char *keyOID,
	unsigned char *key,
	unsigned long *keySize);
typedef int(_cdecl *getcertsignature)
(const hCERTSTORE hStore,
	const unsigned char *certBody,
	const unsigned long bodySize,
	char *sigOID,
	unsigned char *sign,
	unsigned long *signSize);
typedef int(_cdecl *cspoidtohashoidex)
(HCRYPTPROV hProv,
	const char *OID,
	char *hashOID);

typedef int(_cdecl *signmsgopen)
(HCRYPTPROV hProv,
	int Flags,
	hCRYPTMSG *phCrypt);
typedef int(_cdecl *messagename)
(const unsigned char *cmsData,
	const unsigned long dataSize,
	int *senderCount,
	char **senderName,
	int *recipcount,
	char **recipName);
typedef int(_cdecl *signmessage)
(const hCRYPTMSG hCrypt,
	const hCERTSTORE hStore,
	const hCERTCONTEXT MYCert,
	const char *hashOID,
	const char *signOID,
	const char *dataOID,
	const bool Final,
	const unsigned char *dataToSigned,
	const unsigned long dataSize,
	const char *dataDescriptor,
	const unsigned long Flags,
	unsigned char *signedBlob,
	unsigned long *sizeBlob);
typedef int(_cdecl *bintobase)
(unsigned char *inBuf,
	long inSize,
	unsigned char *ouBuf,
	long *outSize);
typedef int(_cdecl *releasecertificatecontext)
(const hCERTSTORE hStore,
	hCERTCONTEXT *phContext);
typedef int(_cdecl *signmsgclose)
(hCRYPTMSG *phCrypt);
typedef int(_cdecl *crtclosestore)(hCERTSTORE *phStore);
typedef int(_cdecl *cspclosecontext)
(HCRYPTPROV *phProv);
typedef int(_cdecl *basetobin)
(unsigned char *inBuf,
	long inSize,
	unsigned char *ouBuf,
	long *outSize);
typedef int(_cdecl *messagesignaturealg)
(const unsigned char *cmsData,
	const unsigned long dataSize,
	char *SignOID,
	char *HashOID);
typedef int(_cdecl *messagedigest)
(const unsigned char *cmsData,
	const unsigned long dataSize,
	unsigned char *Digest,
	unsigned long *digestSize);
typedef int(_cdecl *messagekeyscount)(const unsigned char *cmsData,
	const unsigned long dataSize,
	int  *count);

typedef int(_cdecl *messageinfo)(const unsigned char *cmsData,
	const unsigned long dataSize,
	bool *haveCert,
	char *Time);
typedef int(_cdecl *messagecert)(const unsigned char *cmsData,
	const unsigned long dataSize,
	int *certCount,
	unsigned char **certBody,
	unsigned long *certSize);
typedef int(_cdecl *getmessagecertificate)(const hCERTSTORE hStore,
	const unsigned char *CMSBlob,
	const unsigned long sizeBlob,
	hCERTCOLLECTION *hCollection);
typedef int(_cdecl *freecertificatecollection)(hCERTCOLLECTION *hCollection);
typedef int(_cdecl *getcertificatecollectionex)(const hCERTSTORE hStore,
	const int certCount,
	unsigned char **certBuf,
	unsigned long *certSize,
	hCERTCOLLECTION *hCollection);
typedef int(_cdecl *verifysignmessage)(const hCRYPTMSG hCrypt,
	const hCERTCOLLECTION hCollection,
	const unsigned char *SignedBlob,
	const unsigned long sizeBlob,
	const int Flags,
	char **SignerName,
	char **timeToSigned,
	char **dataDescriptor,
	unsigned char *dataToSigned,
	unsigned long *dataSize,
	char **dataOID,
	int *VerifyRes);
typedef int(_cdecl *getnamecertificate)
(hCERTSTORE hStore,
	const char *DName,
	const char *keyOID,
	const bool isValid,
	const bool isRevoked,
	unsigned char *certBody,
	unsigned long *bodySize,
	char* fname);
typedef int(_cdecl *cspgethash)
(HCRYPTPROV hProv,
	const char *hashOID,
	const bool Final,
	const unsigned char *strReq,
	const unsigned long reqSize,
	unsigned char *strHash,
	unsigned long *hashSize);

getcertificatecollectionex	    GetCertificateCollectionEx = 0;
verifysignmessage                   VerifySignMessage = 0;
freecertificatecollection           FreeCertificateCollection = 0;
getmessagecertificate               GetMessageCertificate;
messagecert			    MessageCert;
messagekeyscount                    MessageKeysCount;
messageinfo                         MessageInfo;
messagedigest                       MessageDigest;
cspopencontext                      CSPOpenContext;
errorstring                         ErrorString;
crtopenstore                        CrtOpenStore;
setldapver                          SetLDAPver;
crtsetstorepropertyext              CrtSetStorePropertyExt;
getmycertificate                    GetMYCertificate;
getcertificatecontext               GetCertificateContext;
getcertsubjectkey                   GetCertSubjectKey;
getcertsignature                    GetCertSignature;
cspoidtohashoidex                   CSPOIDtoHashOIDex;
signmsgopen                         SignMsgOpen;
signmessage                         SignMessage;
bintobase                           BinToBase;
releasecertificatecontext           ReleaseCertificateContext;
signmsgclose                        SignMsgClose;
crtclosestore                       CrtCloseStore;
cspclosecontext                     CSPCloseContext;
basetobin                           BaseToBin;
messagesignaturealg                 MessageSignatureAlg;
messagename                         MessageName;
getnamecertificate                  GetNameCertificate;
cspgethash                          CSPGetHash;

HINSTANCE load_lib(char *lib)
{
#ifdef _WIN32
	return LoadLibraryA(lib);
#else
	return dlopen(lib, RTLD_LAZY);
#endif
}
void lib_free(HINSTANCE Instance)
{
#ifdef _WIN32
	FreeLibrary(Instance);
#else
	dlclose(Instance);
#endif
}
//-----------------------------------------------------------------------
int get_func(HINSTANCE lib)
{
	CSPOpenContext = (cspopencontext)GetProcAddress(lib, "CSPOpenContext");
	if (!CSPOpenContext)
	{
		printf("error load function - %s", "CSPOpenContext");
		return 1;
	}
	CrtOpenStore = (crtopenstore)GetProcAddress(lib, "CrtOpenStore");
	if (!CrtOpenStore)
	{
		printf("error load function - %s", "CrtOpenStore");
		return 1;
	}
	GetMYCertificate = (getmycertificate)GetProcAddress(lib, "GetMYCertificate");
	if (!GetMYCertificate)
	{
		printf("error load function - %s", "GetMYCertificate");
		return 1;
	}
	GetCertificateContext = (getcertificatecontext)GetProcAddress(lib, "GetCertificateContext");
	if (!GetCertificateContext)
	{
		printf("error load function - %s", "GetCertificateContext");
		return 1;
	}
	GetCertSubjectKey = (getcertsubjectkey)GetProcAddress(lib, "GetCertSubjectKey");
	if (!GetCertSubjectKey)
	{
		printf("error load function - %s", "GetCertSubjectKey");
		return 1;
	}
	GetCertSignature = (getcertsignature)GetProcAddress(lib, "GetCertSignature");
	if (!GetCertSignature)
	{
		printf("error load function - %s", "GetCertSignature");
		return 1;
	}
	CSPOIDtoHashOIDex = (cspoidtohashoidex)GetProcAddress(lib, "CSPOIDtoHashOIDex");
	if (!CSPOIDtoHashOIDex)
	{
		printf("error load function - %s", "CSPOIDtoHashOIDex");
		return 1;
	}
	BinToBase = (bintobase)GetProcAddress(lib, "BinToBase");
	if (!BinToBase)
	{
		printf("error load function - %s", "BinToBase");
		return 1;
	}
	ReleaseCertificateContext = (releasecertificatecontext)GetProcAddress(lib, "ReleaseCertificateContext");
	if (!ReleaseCertificateContext)
	{
		printf("error load function - %s", "ReleaseCertificateContext");
		return 1;
	}
	SignMessage = (signmessage)GetProcAddress(lib, "SignMessage");
	if (!SignMessage)
	{
		printf("error load function - %s", "SignMessage");
		return 1;
	}
	GetMessageCertificate = (getmessagecertificate)GetProcAddress(lib, "GetMessageCertificate");
	if (!GetMessageCertificate)
	{
		printf("error load function - %s", "GetMessageCertificate");
		return 1;
	}
	GetCertificateCollectionEx = (getcertificatecollectionex)GetProcAddress(lib, "GetCertificateCollectionEx");
	if (!GetCertificateCollectionEx)
	{
		printf("error load function - %s", "GetCertificateCollectionEx");
		return 1;
	}
	VerifySignMessage = (verifysignmessage)GetProcAddress(lib, "VerifySignMessage");
	if (!VerifySignMessage)
	{
		printf("error load function - %s", "VerifySignMessage");
		return 1;
	}
	MessageInfo = (messageinfo)GetProcAddress(lib, "MessageInfo");
	if (!MessageInfo)
	{
		printf("error load function - %s", "MessageInfo");
		return 1;
	}
	MessageSignatureAlg = (messagesignaturealg)GetProcAddress(lib, "MessageSignatureAlg");
	if (!MessageSignatureAlg)
	{
		printf("error load function - %s", "MessageSignatureAlg");
		return 1;
	}
	MessageDigest = (messagedigest)GetProcAddress(lib, "MessageDigest");
	if (!MessageDigest)
	{
		printf("error load function - %s", "MessageDigest");
		return 1;
	}
	MessageCert = (messagecert)GetProcAddress(lib, "MessageCert");
	if (!MessageCert)
	{
		printf("error load function - %s", "MessageCert");
		return 1;
	}
	MessageKeysCount = (messagekeyscount)GetProcAddress(lib, "MessageKeysCount");
	if (!MessageKeysCount)
	{
		printf("error load function - %s", "MessageKeysCount");
		return 1;
	}
	FreeCertificateCollection = (freecertificatecollection)GetProcAddress(lib, "FreeCertificateCollection");
	if (!FreeCertificateCollection)
	{
		printf("error load function - %s", "FreeCertificateCollection");
		return 1;
	}
	SignMsgOpen = (signmsgopen)GetProcAddress(lib, "SignMsgOpen");
	if (!SignMsgOpen)
	{
		printf("error load function - %s", "SignMsgOpen");
		return 1;
	}
	CSPCloseContext = (cspclosecontext)GetProcAddress(lib, "CSPCloseContext");
	if (!CSPCloseContext)
	{
		printf("error load function - %s", "CSPCloseContext");
		return 1;
	}
	CrtCloseStore = (crtclosestore)GetProcAddress(lib, "CrtCloseStore");
	if (!CrtCloseStore)
	{
		printf("error load function - %s", "CrtCloseStore");
		return 1;
	}
	SignMsgClose = (signmsgclose)GetProcAddress(lib, "SignMsgClose");
	if (!SignMsgClose)
	{
		printf("error load function - %s", "SignMsgClose");
		return 1;
	}
	BaseToBin = (basetobin)GetProcAddress(lib, "BaseToBin");
	if (!BaseToBin)
	{
		printf("error load function - %s", "BaseToBin");
		return 1;
	}
	ErrorString = (errorstring)GetProcAddress(lib, "ErrorString");
	if (!ErrorString)
	{
		printf("error load function - %s", "ErrorString");
		return 1;
	}
	CrtSetStorePropertyExt = (crtsetstorepropertyext)GetProcAddress(lib, "CrtSetStorePropertyExt");
	if (!CrtSetStorePropertyExt)
	{
		printf("error load function - %s", "CrtSetStorePropertyExt");
		return 1;
	}
	SetLDAPver = (setldapver)GetProcAddress(lib, "SetLDAPver");
	if (!SetLDAPver)
	{
		printf("error load function - %s", "SetLDAPver");
		return 1;
	}
	MessageName = (messagename)GetProcAddress(lib, "MessageName");
	if (!MessageName)
	{
		printf("error load function - %s", "MessageName");
		return 1;
	}
	GetNameCertificate = (getnamecertificate)GetProcAddress(lib, "GetNameCertificate");
	if (!GetNameCertificate)
	{
		printf("error load function - %s", "GetNameCertificate");
		return 1;
	}
	CSPGetHash = (cspgethash)GetProcAddress(lib, "CSPGetHash");
	if (!GetNameCertificate)
	{
		printf("error load function - %s", "CSPGetHash");
		return 1;
	}
	return 0;
}
//-----------------------------------------------------------------------
int file_read(char* file, unsigned char **data, long *size);
//-----------------------------------------------------------------------
int main(int argc, char **argv)
{
	HINSTANCE lib = NULL;
	char sigOID[32];
	char hashOID[32];
	char signTime[16];
	char fileSign[260];
	char host[16];
	char port[6];
	char filename[256];
	char **fileCert = NULL;
	char **SignerName = NULL;
	char **senderName = NULL;
	char **timeToSigned = NULL;
	char **dataDescriptor = NULL;
	char **dataOID = NULL;
	char *openText = NULL;
	int  countSender = 0;
	int  certCount = 0;
	int  certsCount = 0;
	long cmcSize = 0;
	int  retCode = 0;
	int j = 0;
	bool haveCert = false;
	unsigned char *dataToSigned = NULL;
	unsigned char *messDigest = NULL;
	unsigned char **certs = NULL;
	unsigned long dataSize = 0;
	unsigned long sizeCAP = 0;
	unsigned long digestSize = 0;
	unsigned long *certsSize = NULL;
	unsigned char *cmcBlob = NULL;
	unsigned char *cmsBlob = NULL;
	unsigned char *txtMessBlob = NULL;
	unsigned char *strHash = NULL;
	unsigned long hashSize = 0;
	unsigned long cmsSize = 0;
	unsigned long txtMessSize = 0;
	hCERTSTORE      hStore = 0;
	HCRYPTPROV      hProv = 0;
	hCRYPTMSG       hSign = 0;
	hCERTCOLLECTION hCollection = 0;
	unsigned char *source = NULL;
	unsigned long sourceSize = 0;
	unsigned long *certSizes = NULL;
	unsigned char **certBodies = NULL;
	int  VerifyRes = 0;

	if (argc != 5)
	{
		printf("Specify parameters (ex.[]$ ./verify /path/filename.sig datafile host port)\n");
		return 1;
	}

	try
	{
		lib = load_lib(strlib);
		if (get_func(lib))
		{
			printf("error load func.\n");
			exit(1);
		}

		strcpy(fileSign, argv[1]);
		strcpy(filename, argv[2]);
		strcpy(host, argv[3]);
		strcpy(port, argv[4]);

		// Открыть файл подписи
		printf("Open sign file : %s\n", fileSign);
		retCode = file_read(fileSign, &cmsBlob, (long *)&cmsSize);
		if (retCode != 0)
		{
			printf("Open file %s Error\n", fileSign);
			throw retCode;
		}
		// Если в формате BASE64 , то сконвертировать в ASN1
		if (cmsBlob[0] == 'M')
		{
			if (cmcBlob)
			{
				delete[] cmcBlob;
			}
			cmcBlob = new unsigned char[MAX_BASE_DENCODED_SIZE(cmsSize)];
			BaseToBin(cmsBlob, cmsSize, cmcBlob, &cmcSize);
			memcpy(cmsBlob, cmcBlob, cmcSize);
			cmsSize = cmcSize;
		}
		// Получить контекст криптопровайдера
		printf("Open CSP Context\n");
		retCode = CSPOpenContext(&hProv, NULL, 25, 0, CRYPT_VERIFYCONTEXT, NULL, 0, NULL, NULL, NULL);
		if (retCode != 0)
		{
			printf("%s  [CSPOpenContext - %d]\n", ErrorString(retCode), retCode);
			throw retCode;
		}
		// Получить контекст хранилища LDAP
		printf("Open Store\n");
		retCode = CrtOpenStore(0, hProv, MORE_ONE_CA, false, NULL, &hStore);
		if (retCode != 0)
		{
			printf("%s  [CrtOpenStore - %d]\n", ErrorString(retCode), retCode);
			throw retCode;
		}
		//Установить версию протокола LDAP
		SetLDAPver(hStore, 3);
		// Настроить хранилище сертификатов
		// если есть возможность загрузить сертификат из файла, то можно вызывать сразу GetCertificateContext 
		printf("Set Store properties\n");
		retCode = CrtSetStorePropertyExt(hStore, MORE_ONE_CA, "t=L;", host, port, 30, NULL, NULL);
		if (retCode != 0)
		{
			printf("%s  [CrtSetStorePropertyExt - %d] \n", ErrorString(retCode), retCode);
			throw retCode;
		}

		printf("Get sign OID + hash OID\n");
		// Получить алгоритмы подписи и хеширования
		retCode = MessageSignatureAlg(cmsBlob, cmsSize, sigOID, hashOID);
		if (retCode != 0)
		{
			printf("%s  [MessageSignatureAlg - %d]\n", ErrorString(retCode), retCode);
			throw retCode;
		}
		else
			printf("MessageSignatureAlg : signOID = %s, hashOID = %s\n", sigOID, hashOID);

		printf("Get message digest\n");
		// Получить хеш на подписанное сообщение
		retCode = MessageDigest(cmsBlob, cmsSize, NULL, &digestSize);
		if (retCode != 0)
		{
			printf("%s  [MessageDigest - %d]\n", ErrorString(retCode), retCode);
			throw retCode;
		}
		messDigest = new unsigned char[digestSize];
		retCode = MessageDigest(cmsBlob, cmsSize, messDigest, &digestSize);
		if (retCode != 0)
		{
			printf("%s  [MessageDigest - %d]\n", ErrorString(retCode), retCode);
			throw retCode;
		}
		else
			printf("MessageDigest : messDigest[%i] = %x %x %x ....\n", digestSize,
				messDigest[0], messDigest[1], messDigest[2]);
		printf("Get message info\n");
		// Получить информацию о времени формирования CMS и наличии сертификата в CMS
		retCode = MessageInfo(cmsBlob, cmsSize, &haveCert, signTime);
		if (retCode != 0)
		{
			printf("%s  [MessageInfo - %d]\n", ErrorString(retCode), retCode);
			throw retCode;
		}
		else
			printf("MessageInfo : signTime = %s\n", signTime);
		if (haveCert)
		{
			printf("Get message certificate\n");
			retCode = MessageCert(cmsBlob, cmsSize, &certCount, NULL, NULL);
			if (retCode != 0)
			{
				printf("%s  [MessageCert - %d]\n", ErrorString(retCode), retCode);
				throw retCode;
			}
			if (certCount)
			{
				certSizes = new unsigned long[certCount];
				certBodies = new unsigned char*[certCount];
				for (j = 0; j < certCount; j++)
					certBodies[j] = new unsigned char[8096];
				retCode = MessageCert(cmsBlob, cmsSize, &certCount, certBodies, certSizes);
				if (retCode)
				{
					printf("%s  [MessageCert - %d]\n", ErrorString(retCode), retCode);
					throw retCode;
				}
				for (j = 0; j < certCount; j++)
				{

					printf("certificate [%d] size = [%d] {%u %u %u ... %u %u %u}\n", j,
						certSizes[j], certBodies[j][0], certBodies[j][1], certBodies[j][2],
						certBodies[j][certSizes[j] - 3], certBodies[j][certSizes[j] - 2],
						certBodies[j][certSizes[j] - 1]);
				}
			}

		}
		else
		{
			printf("\nThere is now any certificate in the sign\n\n");
		}
		printf("MessageCert : certCount = %i\n", certCount);
		printf("Get count signing user\n");
		// Получить информацию о количестве отправителей
		retCode = MessageKeysCount(cmsBlob, cmsSize, &countSender);
		if (retCode != 0)
		{
			printf("%s  [MessageKeysCount - %d]\n", ErrorString(retCode), retCode);
			throw retCode;
		}
		if (countSender<1)
		{
			printf("Not user sign\n");
			throw 301;
		}
		else
			printf("MessageKeysCount = %i\n", countSender);
		SignerName = new char *[countSender];
		for (j = 0; j<countSender; j++) SignerName[j] = new char[260];
		timeToSigned = new char *[countSender];
		for (j = 0; j<countSender; j++) timeToSigned[j] = new char[16];
		dataDescriptor = new char *[countSender];
		for (j = 0; j<countSender; j++) dataDescriptor[j] = new char[260];
		dataOID = new char *[countSender];
		for (j = 0; j<countSender; j++) dataOID[j] = new char[32];
		printf("{%d}\n", countSender);
		printf("Get cerificate collection\n");
		// Получить хендл на коллекцию сертификатов
		if (certCount != 0)
		{
			retCode = GetMessageCertificate(hStore, cmsBlob, cmsSize, &hCollection);
			if (retCode != 0)
			{
				printf("%s  [GetMessageCertificate - %d]\n", ErrorString(retCode), retCode);
				throw retCode;
			}
		}
		else
		{

			retCode = MessageName(cmsBlob, cmsSize, &countSender, NULL, NULL, NULL);
			if (retCode != 0)
			{
				printf("%s  [MessageName - %d]\n", ErrorString(retCode), retCode);
				throw retCode;
			}

			senderName = new char*[countSender];
			senderName[0] = new char[2048];
			certs = new unsigned char*[countSender];
			certsSize = new unsigned long[countSender];

			for (int i = 0; i<countSender; i++)
			{
				retCode = MessageName(cmsBlob, cmsSize, &countSender, &senderName[i], NULL, NULL);
				if (retCode != 0)
				{
					printf("%s  [MessageName - %d]\n", ErrorString(retCode), retCode);
					throw retCode;
				}


				certs[i] = new unsigned char[8192];

				retCode = GetNameCertificate(hStore, senderName[i], "1.2.398.3.10.1.1.2.2",
					true, false, certs[i], &certsSize[i], NULL);
				if (retCode != 0)
				{
					printf("GetNameCertificate, Error = %d (%s)\n", retCode, ErrorString(retCode));
					throw retCode;
				}

			}

			retCode = GetCertificateCollectionEx(hStore, countSender, certs, certsSize, &hCollection);
			if (retCode != 0)
			{
				printf("%s  [GetCertificateCollectionEx - %d]\n", ErrorString(retCode), retCode);
				throw retCode;
			}

		}

		// Получить хендл на CMS-сообщение
		printf("Open sign context\n");
		retCode = SignMsgOpen(hProv, 0, &hSign);
		if (retCode != 0)
		{
			printf("%s  [SignMsgOpen - %d]\n", ErrorString(retCode), retCode);
			throw retCode;
		}
		// Получить размер подписи
		printf("MessageName\n");
		int senderCount = 0;
		retCode = MessageName(cmsBlob, cmsSize, &senderCount, NULL, NULL, NULL);
		if (retCode != 0)
		{
			printf("%s  [MessageName - %d]\n", ErrorString(retCode), retCode);
			throw retCode;
		}
		printf("Sender count [%d]\n", senderCount);
		printf("Verify sign\n");
		retCode = VerifySignMessage(hSign, hCollection, cmsBlob, cmsSize, 0, SignerName,
			timeToSigned, dataDescriptor, NULL, &dataSize, dataOID, &VerifyRes);
		if (retCode != 0)
		{
			printf("%s  [VerifySignMessage - %d]\n", ErrorString(retCode), retCode);
			throw retCode;
		}
		if (dataSize)
		{
			dataToSigned = new unsigned char[dataSize];
			memset(dataToSigned, '\0', dataSize);
		}
		printf("Verify sign\n");
		// Проверить подпись
		retCode = VerifySignMessage(hSign, hCollection, cmsBlob, cmsSize, 0, SignerName,
			timeToSigned, dataDescriptor, dataToSigned, &dataSize, dataOID, &VerifyRes);

		if (retCode != 0)
		{
			printf("%s  [VerifySignMessage - %d]\n", ErrorString(retCode), retCode);
			throw retCode;
		}
		if (VerifyRes != 0)
		{
			printf("%s  VerifyRes = %i\n", ErrorString(VerifyRes), VerifyRes);
			throw VerifyRes;
		}
		else
		{
			if (dataSize)
				printf("VerifySignMessage : dataToSigned[%d] = [%c] [%c]\n", dataSize, dataToSigned[0], dataToSigned[1]);
			else
				printf("\nThere is no source message in CMS.\n\n");
		}
		printf("Sender count [%d]\n", countSender);
		for (j = 0; j<countSender; j++)
		{
			printf("Verify Signature - ok\nUser sign[%d] - %s, timeToSigned[%d] - %s\n", j, SignerName[j], j, timeToSigned[j]);
		}

		// Открыть файл txt
		printf("Open sign file : %s\n", filename);
		retCode = file_read(filename, &txtMessBlob, (long *)&txtMessSize);
		if (retCode != 0)
		{
			printf("Open file %s Error\n", filename);
			throw retCode;
		}
		//Получить хеш txt файла 

		retCode = CSPGetHash(hProv, "1.2.398.3.10.1.3.3", true, txtMessBlob, txtMessSize, strHash, &hashSize);
		if (retCode != 0)
		{
			printf("%s  [CSPGetHash - %d]\n", ErrorString(retCode), retCode);
			throw retCode;
		}

		strHash = new unsigned char[hashSize];

		retCode = CSPGetHash(hProv, "1.2.398.3.10.1.3.3", true, txtMessBlob, txtMessSize, strHash, &hashSize);
		if (retCode != 0)
		{
			printf("%s  [CSPGetHash - %d]\n", ErrorString(retCode), retCode);
			throw retCode;
		}

		//Сравнение хешей  messDigest (hash of cms file) и полученного хеша из txt файла
		if (memcmp(messDigest, strHash, hashSize) == 0)
		{
			printf("Verify Hash - ok");

		}
		else
		{
			printf("Verify Hash - error");
		}



	}
	catch (int err)
	{
		printf("catch ... Error - %d\n", err);
	}
	// Освободить хенлды и переменные
	if (hCollection) FreeCertificateCollection(&hCollection);
	if (hSign) SignMsgClose(&hSign);
	if (hStore) CrtCloseStore(&hStore);
	if (hProv) CSPCloseContext(&hProv);
	if (dataOID)
	{
		for (j = 0; j<countSender; j++) delete[] dataOID[j];
		delete[] dataOID;
	}
	if (dataDescriptor)
	{
		for (j = 0; j<countSender; j++) delete[] dataDescriptor[j];
		delete[] dataDescriptor;
	}
	if (timeToSigned)
	{
		for (j = 0; j<countSender; j++) delete[] timeToSigned[j];
		delete[] timeToSigned;
	}
	if (SignerName)
	{
		for (j = 0; j<countSender; j++) delete[] SignerName[j];
		delete[] SignerName;
	}
	if (fileCert)
	{
		for (j = 0; j<certsCount; j++) { delete[] fileCert[j]; }
		delete[] fileCert;
	}
	if (certs)
	{
		for (j = 0; j<certsCount; j++) { delete[] certs[j]; }
		delete[] certs;
	}
	if (certSizes) delete[] certSizes;
	if (certBodies)
	{
		for (j = 0; j < certCount; j++) { delete[] certBodies[j]; }
		delete[] certBodies;
	}

	if (senderName)
	{
		for (j = 0; j<countSender; j++) { delete[] senderName[j]; }
		delete[] senderName;
	}


	if (certsSize) { delete[] certsSize; }
	if (cmsBlob) { delete[] cmsBlob; }
	if (cmcBlob) { delete[] cmcBlob; }
	if (messDigest) { delete[] messDigest; }
	if (strHash) { delete[] strHash; }
	if (dataToSigned) { delete[] dataToSigned; }
	if (lib) { lib_free(lib); }
	printf("Exit\n");
	return 0;
}
//-----------------------------------------------------------------------
int file_read(char* file, unsigned char **data, long *size)
{
	FILE *in = NULL;
	struct stat  st;
	if (stat(file, &st)) return 1; // File not found ... 
	*size = st.st_size;
	*data = new unsigned char[*size];
	if ((in = fopen(file, "rb")) == NULL)
	{
		free(*data);
		*size = 0;
		*data = NULL;
		return 2;  // File not opened ... 
	}
	fread(*data, *size, 1, in);
	fclose(in);
	return 0;
}
