#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 CERTIFICATE "MIICgjCCAiugAwIBAgIgYdfrHjMxbdNljpwLGIA2ByiVGMrIFsJP6JBdWruAdKswDgYKKwYBBAG1EQECAgUAMCwxCzAJBgNVBAYTAktaMQ4w\
                     DAYDVQQKEwVHQU1NQTENMAsGA1UEAxQEUk9PVDAiGA8yMDA3MDkxMDA0NTAyNFoYDzIwMTIwOTEwMDQ1MDI0WjAsMQ0wCwYDVQQDFARPQ1NQ\
                     MQ4wDAYDVQQKEwVHQU1NQTELMAkGA1UEBhMCS1owYzAOBgorBgEEAbURAQICBQADUQAGAgAAOqoAAABFQzEAAgAAwZVniJZI9tuagWEwGXfT\
                     rvY9BwZelHS8fz2TjFUdkUgWywz5yAR+zwxFYRYZ/n0kDCyKnw+Eoflh5Gr3NbGYhaOCAQswggEHMGoGA1UdIwRjMGGAIDmw7vMUjm7UHtRH\
                     DN9yZVMiH5zenUwDtl3kZn15PthWoRuGGXVybDovLzE5Mi4xNjguNy4yMjI6NjIyMjKCIDmw7vMUjm7UHtRHDN9yZVMiH5zenUwDtl3kZn15\
                     PthWMCkGA1UdDgQiBCBh1+seMzFt02WOnAsYgDYHKJUYysgWwk/okF1au4B0qzALBgNVHQ8EBAMCBsAwEwYDVR0lBAwwCgYIKwYBBQUHAwkw\
                     DAYDVR0TBAUwAwIBADANBgkrBgEFBQcwAQUEADAvBgNVHR8EKDAmMCSgHqAchhp1cmw6Ly8xOTIuMTY4LjcuMjIyOjYyMjIyAIECAWYwDgYK\
                     KwYBBAG1EQECAgUAA0EA3ZveWdepxXVfQDr70Fwa3YuVE0/gy7u5bgmNon+Dw6vO09N5hpFKAkynAdnwaab/sfvQjBUob9NU/GlHyyM6mA=="

					 
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 char* (_cdecl *errorstring) (const int err);							   
typedef int (_cdecl *basetobin)
							  (unsigned char *inBuf, 
							   long inSize, 
							   unsigned char *ouBuf,
							   long *outSize);
typedef int (_cdecl *getcertvalidinfo)
							  (const hCERTSTORE hStore,
                               const unsigned char *certBody,
                               const unsigned long bodySize,
                               char *notBefore,
                               char *notAfter);						   
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 *getcertsubjectinfo)
                              (const hCERTSTORE hStore,
                               const unsigned char *certBody,
                               const unsigned long bodySize,
                               char *CName,
                               char *DName);		
typedef int (_cdecl *gettime) (char *_time);							   
typedef int (_cdecl *crtverifytimevalidity)
                              (const hCERTSTORE hStore,
                               const char *pTime,
                               const unsigned char *certBody,
                               const unsigned long bodySize);
typedef int (_cdecl *getcertsubjectnumber)
                              (const hCERTSTORE hStore,
                               const unsigned char *certBody,
                               const unsigned long bodySize,
                               unsigned char *serNum,
                               unsigned long *numSize);							   
							   
cspopencontext         CSPOpenContext;
crtopenstore           CrtOpenStore;
crtclosestore          CrtCloseStore;
cspclosecontext        CSPCloseContext;
errorstring            ErrorString;								 
basetobin              BaseToBin;
getcertvalidinfo       GetCertValidInfo;
getcertsubjectkey      GetCertSubjectKey;
getcertsignature       GetCertSignature;
getcertsubjectinfo     GetCertSubjectInfo;
gettime                GetTime;
crtverifytimevalidity  CrtVerifyTimeValidity;
getcertsubjectnumber   GetCertSubjectNumber;

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;
   }
   ErrorString = (errorstring) GetProcAddress(lib,"ErrorString");
   if(!ErrorString)
   {
       printf("error load function - %s", "ErrorString");
       return 1;
   }   
   BaseToBin = (basetobin) GetProcAddress(lib,"BaseToBin");
   if(!BaseToBin)
   {
       printf("error load function - %s", "BaseToBin");
       return 1;
   }    
   GetCertValidInfo = (getcertvalidinfo) GetProcAddress(lib,"GetCertValidInfo");
   if(!GetCertValidInfo)
   {
       printf("error load function - %s", "GetCertValidInfo");
       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;
   }   
   GetCertSubjectInfo = (getcertsubjectinfo) GetProcAddress(lib,"GetCertSubjectInfo");
   if(!GetCertSubjectInfo)
   {
       printf("error load function - %s", "GetCertSubjectInfo");
       return 1;
   }
   GetTime = (gettime) GetProcAddress(lib,"GetTime");
   if(!GetTime)
   {
       printf("error load function - %s", "GetTime");
       return 1;
   }
   CrtVerifyTimeValidity = (crtverifytimevalidity) GetProcAddress(lib,"CrtVerifyTimeValidity");
   if(!CrtVerifyTimeValidity)
   {
       printf("error load function - %s", "CrtVerifyTimeValidity");
       return 1;
   }
   GetCertSubjectNumber = (getcertsubjectnumber) GetProcAddress(lib,"GetCertSubjectNumber");
   if(!GetCertSubjectNumber)
   {
       printf("error load function - %s", "GetCertSubjectNumber");
       return 1;
   }   

   return 0;
}
//---------------------------------------------------------------------------
void b2h(unsigned char *inbuf, long  insize, unsigned char *oubuf)
{
char *HAlf =(char*)"0123456789ABCDEF";
long l;
memset(oubuf,0,sizeof(oubuf));
for (l=0;l<insize;l++) 
{  
  
  oubuf[2*l]    =(unsigned char) HAlf[inbuf[(int) l]>>4];
  oubuf[(2*l)+1]=(unsigned char) HAlf[inbuf[(int) l]&0x0F];
  }
}
//---------------------------------------------------------------------------
//Для вызова следующих функций, необходимо, что бы тело сертификата было загружено в переменную unsigned char *Body
//Каким способом был получен сертификат (из хранилища LDAP, загружен из файла, объявлен в заголовке) не имеет значения
int CertificateInfo (hCERTSTORE Store,unsigned char *Body,unsigned long Size)
{
int code, ret = 0;
char Before[32];
char After[32];
unsigned char key[8096];
unsigned char *hkey=NULL;
unsigned long ksize = 8096;
char CName[64], DName[256];
char SignOID[256];
SignOID[0] = 0;
try
{
  //получить информацию о сроке действия сертификата
  code = GetCertValidInfo (Store,Body,Size,Before,After);
  if (code) throw code;
  printf("from date = %s\nto   date = %s\n", Before,After);
  //извлечь открытый ключ
  code = GetCertSubjectKey (Store,Body,Size,NULL,key,&ksize);
  if (code) throw code;
  hkey = (unsigned char*) calloc (ksize*2+1, sizeof(unsigned char));
  b2h(key,ksize,hkey);
  printf("open key  = %s, keylen = %d\n", hkey, ksize);
  free (hkey);
  //извлечь подпись сертификата
  memset(&key, 0 ,8096);
  ksize = 8096;
  code = GetCertSignature (Store,Body,Size,SignOID,key,&ksize);
  if (code) throw code;
  hkey = (unsigned char*) calloc (ksize*2+1, sizeof(unsigned char));
  b2h(key,ksize,hkey);
  printf("signature = %s\n", hkey);
  free (hkey); hkey = NULL;
  //получить информацию о владельце сертификата
  code = GetCertSubjectInfo (Store,Body,Size,CName,DName);
  if (code) throw code;
  printf("CN        = %s\nDN        = %s\n", CName, DName);
  code = GetTime(Before);
  if (code) throw code;
  //проверить валидность сертификата.
  code = CrtVerifyTimeValidity (Store,Before, Body, Size);
  if (code) throw code;
  printf("certificate is valid\n");
  //получить информацию о серийном номере сертификата
  memset(key,0,sizeof(key));
  code =  GetCertSubjectNumber(Store, Body, Size, key, &ksize);
  if (code) throw code;
  hkey = (unsigned char*) calloc (ksize*2+1, sizeof (unsigned char));
  b2h(key,ksize,hkey);
  printf ("serial num= %s\n",hkey);
  free (hkey); hkey = NULL;
}
catch (int err)
{
  ret = err;
  printf("%s\n",ErrorString(ret));
}
return ret;
}
//---------------------------------------------------------------------------
int main(void)
{

	HINSTANCE       lib		= NULL;
	int 			ret 	= 0;
	int 			code 	= 0;
	hCERTSTORE 		hStore 	= 0;
	HCRYPTPROV 		hP     	= 0;
	unsigned char 	*binCert=NULL;
	long          	binSize;
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;
  }
  //получение  сертификата
  //в этом примере не вызывается функция CrtSetStorePropertyExt, т.к. получение сертификата выполняется не из LDAP-хранилища, а из константы CERTIFICATE
  binCert = (unsigned char*) calloc (sizeof(CERTIFICATE),sizeof(unsigned char));
  code = BaseToBin ((unsigned char*)CERTIFICATE, sizeof(CERTIFICATE), binCert, &binSize);
  if (code)
  {
    printf("%s [BaseToBin: error = %d]\n", ErrorString(code), code);
    throw code;
  }
  //получение данных
  code = CertificateInfo (hStore,binCert,binSize);
}
catch(int er){ret=er;}
if (binCert) free (binCert);
//закрыть хранилище сертификатов
if( hStore ) 
{
  CrtCloseStore(&hStore); 
  hStore = (hCERTSTORE) NULL;
}
//удалить контекст криптопровайдера
if( hP )
{
  CSPCloseContext(&hP); 
  hP = (HCRYPTPROV) NULL;
}
if (lib) lib_free(lib);
return ret;
}
