#include  <stdio.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
typedef unsigned long hPKICONTEXT;
typedef unsigned long hCRYPTMSG;
typedef unsigned long hCERTSTORE;
typedef unsigned long HCRYPTPROV;
typedef unsigned long hCERTCOLLECTION;
#ifndef _WIN32
  typedef unsigned long DWORD;
  typedef unsigned char BYTE;
  typedef void *HINSTANCE;
  typedef char CHAR;
#endif
// Константы для хранилища :
#define STORE_TYPE "t=A;"
#define STORE_HOST "127.0.0.1"
#define STORE_PORT "62222"
#define DN "CN=ROOT;O=LOCAL;C=KZ;"

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 *crtclosestore)    (hCERTSTORE *phStore);
typedef int (_cdecl *cspclosecontext)  (HCRYPTPROV *phProv);
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 *getgroupca)
							  (hCERTSTORE hStore,
							   const char *groupName,
                               const char *dataValid,
                               const bool isValid,
                               int *certCount,
                               unsigned char **certBody,
                               unsigned long *bodySize);
typedef char* (_cdecl *errorstring) (const int err);

cspopencontext         CSPOpenContext;
crtopenstore           CrtOpenStore;
crtclosestore          CrtCloseStore;
cspclosecontext        CSPCloseContext;
crtsetstorepropertyext CrtSetStorePropertyExt;
getgroupca             GetGroupCA;
errorstring            ErrorString;


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;
   }
   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;
   }
   CrtSetStorePropertyExt = (crtsetstorepropertyext)  GetProcAddress(lib,"CrtSetStorePropertyExt");
   if(!CrtSetStorePropertyExt)
   {
       printf("error load function - %s", "CrtSetStorePropertyExt");
       return 1;
   }
   GetGroupCA = (getgroupca)  GetProcAddress(lib,"GetGroupCA");
   if(!GetGroupCA)
   {
       printf("error load function - %s", "GetGroupCA");
       return 1;
   }   
   ErrorString = (errorstring) GetProcAddress(lib,"ErrorString");
   if(!ErrorString)
   {
       printf("error load function - %s", "ErrorString");
       return 1;
   }   
   return 0;
}
int main(void)
{
 HINSTANCE          lib    	= NULL;
 int 				ret  	= 0;
 int 				code 	= 0;
 int 				i, count;
 hCERTSTORE 		hStore 	= 0;
 HCRYPTPROV 		hP     	= 0;
 int 				certCount;
 unsigned char 		**certBody = NULL;
 unsigned long 		*bodySize  = NULL;
 try
 {
  lib = load_lib(strlib);
  if( get_func(lib) )
  {
     printf("error load func.\n");
     exit(1);
  }
  //получить контекст криптопровайдера
  code = CSPOpenContext(&hP,NULL, 25, 0, CRYPT_VERIFYCONTEXT, NULL, 0, NULL, 0, NULL);
  if( code )
  {
    printf("%s [CSPOpenContext: error = %d]\n",ErrorString(code), code);
    throw code;
  }
  //открыть хранилище сертификатов
  code = CrtOpenStore(0, hP, 0, false, NULL, &hStore);
  if( code )
  {
    printf("%s [CrtOpenStore: error = %d]\n",ErrorString(code), code);
    throw code;
  }
  //настроить хранилище сертификатов (обязательно, при подключении к удалённому хранилищу LDAP)
  code = CrtSetStorePropertyExt(hStore, 0, STORE_TYPE, STORE_HOST, STORE_PORT, 300, 0, 0);
  if( code )
  {
    printf("%s [CrtSetStorePropertyExt: error = %d]\n",ErrorString(code), code);
    throw code;
  }
  //получить сертификаты CA по DN имени (функция работает с LDAP хранилищем)
  //получить количествово сертификатов
  code = GetGroupCA (hStore, DN, NULL, true, &certCount, NULL, NULL);
  if (code)
  {
    printf("%s [GetGroupCA: error = %d]\n",ErrorString(code), code);
    throw code;
  }
  if (certCount)
  {
    count = certCount;
    bodySize = (unsigned long*) calloc (certCount,sizeof(unsigned long));
    //получить размеры сертификатов
    code = GetGroupCA (hStore, DN, NULL, true, &certCount,NULL, bodySize);
    if (code)
    {
      printf("%s [GetGroupCA: error = %d]\n",ErrorString(code), code);
      throw code;
    }
    certBody = (unsigned char**) calloc (certCount,sizeof(unsigned char*));
    for(i=0;i<certCount;i++)
      certBody[i] = (unsigned char*) calloc(bodySize[i],sizeof(unsigned char));
    //получить сертификаты
    code = GetGroupCA (hStore, DN, NULL, true, &certCount, certBody, bodySize);
    if (code)
    {
      printf("%s [GetGroupCA: error = %d]\n",ErrorString(code), code);
      throw code;
    }
    printf ("Found %d CA certificates\n",certCount);
  }
  else {printf ("Certificate Ca not found\n"); throw code; }
  
 }
catch(int er){ret=er;}
if (certBody)
{
  for (i=0; i<count; i++)
    if (certBody[i]) {free(certBody[i]); certBody[i] = NULL;}
  free (certBody); certBody = NULL;
}
if (bodySize) {free (bodySize); bodySize = NULL;}
//закрыть хранилище сертификатов
if( hStore ) 
{
  CrtCloseStore(&hStore); 
  hStore = (hCERTSTORE) NULL;
}
//удалить контекст криптопровайдера
if( hP )
{
  CSPCloseContext(&hP); 
  hP = (HCRYPTPROV) NULL;
}
if (lib) lib_free(lib);
return ret;
}
