#include <stdio.h>
#include <time.h>
#include <sys/stat.h>
#ifdef _WIN32
  #include <windows.h>
  #define CRYPT_VERIFYCONTEXT     0xF0000000
  #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 CRYPT_VERIFYCONTEXT 0xF0000000
  #define TRUE 1
  #define FALSE 0
#endif
#ifndef _WIN32
  typedef unsigned long DWORD;
  typedef unsigned char BYTE;
  typedef void *HINSTANCE;
  typedef char CHAR;
#endif
typedef unsigned long hCRYPTMSG;
typedef unsigned long hCERTSTORE;
typedef unsigned long HCRYPTPROV;
typedef unsigned long hCERTCOLLECTION;

#define CRT_STORE_PROV_LDAP     0
#define AT_KEYEXCHANGE          1
#define AT_SIGNATURE            2

//Константы для Хранилища
#define STORE_HOST "127.0.0.1"
#define STORE_PORT "62222"


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

  typedef int (_cdecl *D_CrtOpenStore)(DWORD StoreProvider,
                                   HCRYPTPROV hProv,
                                   unsigned long dwFlags,
                                   bool  bFlag,
                                   const void *pvParam,
                                   hCERTSTORE *phStore);
  typedef int (_cdecl *D_CrtCloseStore)(hCERTSTORE *phStore);
  typedef int (_cdecl *D_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 *D_ErrorString)(const int err);
  typedef DWORD (_cdecl *D_CSPOpenContext)(HCRYPTPROV *phProv,
                                       char *pszContainer,
                                       DWORD dwProvType,
                                       DWORD dwProvParam,
                                       DWORD dwFlags,
                                       BYTE * pbSignature,
                                       DWORD dwSigLen,
                                       BYTE * pbContainer,
                                       DWORD * dwContLen,
                                       HINSTANCE *phLib);
  typedef int (_cdecl *D_CSPSetProvParam)(DWORD param, BYTE  *pbData);
  typedef int (_cdecl *D_GetMYCertificate)(hCERTSTORE hStore,
                                         const char *DName,
                                         const unsigned long keySpec,
                                         const bool isCA,
                                         unsigned char *certBody,
                                         unsigned long *bodySize);
  typedef int (_cdecl *D_CSPCloseContext)(HCRYPTPROV *phProv);
  typedef int (_cdecl *D_GetCACertificateKey)
                           (hCERTSTORE hStore,
                            const char *DName,
                            const char *keyOID,
                            const bool isValid,
                            unsigned char *certBody,
                            unsigned long *bodySize);

//---------------------------------------------------------------------------
  D_CrtOpenStore           CrtOpenStore=0;
  D_CrtCloseStore          CrtCloseStore=0;
  D_CrtSetStorePropertyExt CrtSetStorePropertyExt=0;
  D_ErrorString            ErrorString=0;
  D_CSPOpenContext         CSPOpenContext=0;
  D_CSPSetProvParam        CSPSetProvParam=0;
  D_GetMYCertificate       GetMYCertificate=0;
  D_CSPCloseContext        CSPCloseContext=0;
  D_GetCACertificateKey    GetCACertificateKey=0;
HINSTANCE hInstSTRLib =  NULL;
//---------------------------------------------------------------------------
int LoadLib()
{
   int ret = 0;
   #ifdef _WIN32
      hInstSTRLib = LoadLibraryA(strlib);
   #else
      hInstSTRLib = dlopen(strlib,RTLD_LAZY);
   #endif
   try
   {
      if( hInstSTRLib == NULL ) throw 1;
      CrtOpenStore = (D_CrtOpenStore) GetProcAddress (hInstSTRLib, "CrtOpenStore");
      if( CrtOpenStore == NULL ) throw 2;
      CrtCloseStore = (D_CrtCloseStore) GetProcAddress (hInstSTRLib, "CrtCloseStore");
      if( CrtCloseStore == NULL ) throw 3;
      CrtSetStorePropertyExt = (D_CrtSetStorePropertyExt) GetProcAddress (hInstSTRLib, "CrtSetStorePropertyExt");
      if( CrtSetStorePropertyExt == NULL ) throw 4;
      ErrorString = (D_ErrorString) GetProcAddress (hInstSTRLib, "ErrorString");
      if( ErrorString == NULL ) throw 5;
      CSPOpenContext = (D_CSPOpenContext) GetProcAddress (hInstSTRLib, "CSPOpenContext");
      if( CSPOpenContext == NULL ) throw 6;
      CSPSetProvParam = (D_CSPSetProvParam) GetProcAddress (hInstSTRLib, "CSPSetProvParam");
      if( CSPSetProvParam == NULL ) throw 7;
      GetMYCertificate = (D_GetMYCertificate) GetProcAddress (hInstSTRLib, "GetMYCertificate");
      if( GetMYCertificate == NULL ) throw 8;
      CSPCloseContext = (D_CSPCloseContext) GetProcAddress (hInstSTRLib, "CSPCloseContext");
      if( CSPCloseContext == NULL ) throw 8;
      GetCACertificateKey = (D_GetCACertificateKey) GetProcAddress (hInstSTRLib, "GetCACertificateKey");
      if( GetCACertificateKey == NULL ) throw 9;
   }
   catch(int er){ret = er;}
   return ret;
}
//---------------------------------------------------------------------------
void lib_free( HINSTANCE Instance )
{
#ifdef _WIN32
  FreeLibrary(Instance);
#else
  dlclose(Instance);
#endif
}
//------------------------------------------------------------------------------
int main(int argc, char* argv[])
{            
   
   int ret = 0;
   int code = 0;
   hCERTSTORE hStore = 0;
   HCRYPTPROV hP = 0;
   unsigned char CertSignBlob[2048];
   unsigned long CertSignSize = 2048;
   unsigned char CertExchBlob[2048];
   unsigned long CertExchSize = 2048;
   char DName[256]="cn=1;o=GAMMA;c=KZ";
   char Profile[256];

   if(argc<2)
   {
      printf("Specify sign file (ex.[]$ ./getmycert /path/filename.bin [key container])\n");
      return 1;
   }
     #ifdef WIND32
      sprintf(Profile,"profile://%s",argv[1]);
     #else
      sprintf(Profile,"%s",argv[1]);
     #endif
   try
   {
   //Загрузить библиотеку
      code = LoadLib();
      if( code ) throw code;
      //Открыть контекст CSP
      code = CSPOpenContext(&hP, (char *)Profile, 25, 0, 0, NULL, 0, NULL, NULL, NULL);
      if( code ) throw code;
      // Открыть конекст хранилища
      code = CrtOpenStore(CRT_STORE_PROV_LDAP, hP, 0, false, NULL, &hStore);
      if( code ) throw code;
      // Установить параметры хранилища
      // всегде необходимо вызывать перед вызовом GetMYCertificate
	  code = CrtSetStorePropertyExt(hStore, 0, DName, STORE_HOST, STORE_PORT, 300, 0, 0);
      if( code ) throw code;
      //Получить собственные сертификаты
      code = GetMYCertificate(hStore, DName, AT_SIGNATURE, false, CertSignBlob, &CertSignSize);
      if( code ) throw code;
      code = GetMYCertificate(hStore, DName, AT_KEYEXCHANGE, false, CertExchBlob, &CertExchSize);
      if( code ) throw code;
      //Если не произошло ошибки, то сертификаты хранятся в CertSignBlob и CertExchBlob соответственно.
	  printf("Getting own certificates is done, in CertSignBlobs & CertExchBlob\n");
   }
   catch(int er){ret=er;}
   if( hStore ) { CrtCloseStore(&hStore); hStore = 0;}
   if( hP ) { CSPCloseContext(&hP); hP = 0;}
   if( hInstSTRLib ) { lib_free(hInstSTRLib); hInstSTRLib = NULL; }
   if (ret!=0) printf("Getting own certificates error [code = %d]\n", ret);
   return ret;
}
//---------------------------------------------------------------------------
