#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.1.0.0.sl"
  #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 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);

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;
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;
   }   
   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 **fileCert             =  NULL;
   char **SignerName           =  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 long cmsSize       =     0;
   hCERTSTORE      hStore      =     0;
   HCRYPTPROV      hProv       =     0;
   hCRYPTMSG       hSign       =     0;
   hCERTCOLLECTION hCollection =     0;
   FILE *f                     =  NULL;
   unsigned char *source       =  NULL;
   unsigned long sourceSize    =     0;
   unsigned long *certSizes    =  NULL;
   unsigned char **certBodies  =  NULL;
   int  VerifyRes              =     0;
 if(argc<2)
 {
    printf("Specify parameters (ex.[]$ ./verify /path/filename.sig [file of certificate(-s)])\n");
    return 1;
 }
 //Запоминаем названия файлов сертификатов, если они есть
 if (argc>2)
 {
   fileCert = new char *[argc-2];
   for(int j=0;j<argc-2;j++)
   {
     if(argv[j+2])
     {
       fileCert[j] = new char [260];
       strcpy(fileCert[j],argv[j+2]);
     }
     else
       break;
   }
 }
 try
 {
   lib = load_lib(strlib);
   if( get_func(lib) )
   {
     printf("error load func.\n");
     exit(1);
   }      
   // Открыть файл подписи
   strcpy(fileSign,  argv[1]);
   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;
   }
   // Открыть хранилище сертификатов
   // устанавливать парметры хранилища в данном случае нет необходимости, т.к. сертификаты загружаются из файлов
   printf("Open Store L\n");
   retCode = CrtOpenStore(0, hProv, 0, false, NULL, &hStore);
   if(retCode!=0)
   {
     printf("%s  [CrtOpenStore - %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
   {
     if(fileCert!=NULL)
     {
       certs = new unsigned char *[countSender];
       certsSize = new unsigned long [countSender];
       for(int j=0;j<countSender;j++)
       {
         retCode = file_read(fileCert[j],&certs[j],(long *) &certsSize[j]);
         if(retCode!=0)
         {
           printf("Error file_read: %s\n",fileCert[j]);
           throw retCode;
         }
		 certsCount++;
		 printf("certsCount [%d] \n", certsCount);
       }
       retCode = GetCertificateCollectionEx(hStore,countSender,certs,certsSize,&hCollection);
       if(retCode!=0)
       {
         printf("%s  [GetCertificateCollectionEx - %d]\n",ErrorString(retCode), retCode);
         throw retCode;
       }
     }
     else
     {
       printf("There are no any certificates in parameters\n");
       throw 1;
     }
   }
   // Получить хендл на 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 - ok\nUser sign[%d] - %s, timeToSigned[%d] - %s\n", j, SignerName[j], j, timeToSigned[j]);
   }
 }
 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( certsSize ) delete [] certsSize;
 if( cmsBlob ) { delete [] cmsBlob; }
 if( cmcBlob ) { delete [] cmcBlob; }
 if( messDigest ) delete [] messDigest;
 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; 
 }
