#include <stdio.h>
#include <time.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 SIGN_CERT "sign.cer"
#define EXCH_CERT "exch.cer"

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 *createpkicontext) (hPKICONTEXT *hPKI);
typedef int (_cdecl *crtrevoke)
                              (hPKICONTEXT hPKI,
                               const unsigned char *crtSign,
                               const unsigned long crtSignSize,
                               const unsigned char *crtExch,
                               const unsigned long crtExchSize,
                               const int revReason,
                               const char *revDate,
                               const char *DName,
                               const char *Comment,
                               const char *transID,
                               unsigned char **cmcBlob,
                               unsigned long *sizeBlob);
typedef int (_cdecl *getcertsubjectinfo)
                              (const hCERTSTORE hStore,
                               const unsigned char *certBody,
                               const unsigned long bodySize,
                               char *CName,
                               char *DName);
typedef int (_cdecl *releasepkicontext) (hPKICONTEXT *phPKI);
typedef int (_cdecl *errorstring) (const int err);

cspopencontext      CSPOpenContext;
crtopenstore       CrtOpenStore;
crtclosestore      CrtCloseStore;
cspclosecontext    CSPCloseContext;
createpkicontext   CreatePKIContext;
crtrevoke          CrtRevoke;
getcertsubjectinfo GetCertSubjectInfo;
releasepkicontext  ReleasePKIContext;
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;
   }
   ErrorString = (errorstring) GetProcAddress(lib,"ErrorString");
   if(!ErrorString)
   {
       printf("error load function - %s", "ErrorString");
       return 1;
   }
   CreatePKIContext = (createpkicontext) GetProcAddress(lib,"CreatePKIContext");
   if(!CreatePKIContext)
   {
       printf("error load function - %s", "CreatePKIContext");
       return 1;
   }
   CrtRevoke = (crtrevoke) GetProcAddress(lib,"CrtRevoke");
   if(!CrtRevoke)
   {
       printf("error load function - %s", "CrtRevoke");
       return 1;
   }
   GetCertSubjectInfo = (getcertsubjectinfo) GetProcAddress(lib,"GetCertSubjectInfo");
   if(!GetCertSubjectInfo)
   {
       printf("error load function - %s", "GetCertSubjectInfo");
       return 1;
   }
   ReleasePKIContext = (releasepkicontext) GetProcAddress(lib,"ReleasePKIContext");
   if(!ReleasePKIContext)
   {
       printf("error load function - %s", "ReleasePKIContext");
       return 1;
   }
   return 0;
}
int main(void)
{
 int                   code     = 0;
 FILE                  *in      = NULL;
 long                  l        = 0;
 unsigned char         *sign    = NULL;
 unsigned char         *exch    = NULL;
 unsigned long         signSize, exchSize;
 HINSTANCE             lib      = NULL;
 hPKICONTEXT           hPKI     = 0;
 HCRYPTPROV            hP       = 0;
 hCERTSTORE            hStore   = 0;
 unsigned char         *blob    = NULL;
 unsigned long         blobSize = 0;
 char                  curTime[18], DName[256];
 struct tm t;
 time_t lt;
 try
 {
   lib = load_lib(strlib);
   if( get_func(lib) )
   {
     printf("error load func.\n");
     exit(1);
   }
   printf("Open certificate : %s\n", SIGN_CERT);
   if( (in = fopen(SIGN_CERT, "rb"))==NULL ) throw 1;
   l=ftell(in);
   fseek(in, 0L, SEEK_END);
   signSize=ftell(in);
   fseek(in, l, SEEK_SET);
   printf("signCertificateSize = [%d]\n", signSize);
   sign = (unsigned char*) calloc (signSize+1, sizeof(unsigned char));
   fread(sign, signSize, 1, in);
   fclose(in);

   printf("Open certificate : %s\n", EXCH_CERT);
   if( (in = fopen(EXCH_CERT, "rb"))==NULL ) throw 1;
   l=ftell(in);
   fseek(in, 0L, SEEK_END);
   exchSize=ftell(in);
   fseek(in, l, SEEK_SET);
   printf("exchCertificateSize = [%d]\n", exchSize);
   exch = (unsigned char*) calloc (exchSize+1, sizeof(unsigned char));
   fread(exch, exchSize, 1, in);
   fclose(in);
   //
   // Открываем контекст криптопровайдера
   //
   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;
   }
  //
  // Получаем хендл на CMC
  //
  code = CreatePKIContext (&hPKI);
  if( code )
  {
    printf("%s [CreatePKIContext: error = %d]\n",ErrorString(code), code);
    throw code;
  }
  code = GetCertSubjectInfo(hStore, sign, signSize, DName, NULL);
  if( code )
  {
    printf("%s [GetCertSubjectInfo: error = %d]\n",ErrorString(code), code);
    throw code;
  }
  lt=time(NULL);
  memcpy(&t,localtime(&lt),sizeof(struct tm));
  sprintf(curTime,"%04d%02d%02d%02d%02d%02dZ",t.tm_year+1900,t.tm_mon+1,t.tm_mday,t.tm_hour,t.tm_min,t.tm_sec);
  //
  // Формируем запрос на отзыв
  //
  code = CrtRevoke(hPKI, sign, signSize, exch, exchSize, 1, curTime, DName, "Test comment", "4BB3DBF86B728A76CD0F88B9C10ACCCD", &blob, &blobSize);
  if( code )
  {
    printf("%s [CrtRevoke: error = %d]\n",ErrorString(code), code);
    throw code;
  }
  in=fopen("revoke.bin","wb");
  fwrite(blob,sizeof(unsigned char),blobSize,in);
  fclose(in);
}
catch(int er){code=er;}
if ( sign )
{
  free ( sign ); sign = NULL;
}
if ( exch )
{
  free ( exch ); sign = NULL;
}
//закрыть хранилище сертификатов
if( hStore )
{
  CrtCloseStore(&hStore);
  hStore = (hCERTSTORE) NULL;
}
//удалить контекст криптопровайдера
if( hP )
{
  CSPCloseContext(&hP);
  hP = (HCRYPTPROV) NULL;
}
// Удалить хепдел CMC
if ( hPKI )
{
  ReleasePKIContext(&hPKI);
  hPKI = 0;
}
if (lib) lib_free( lib );
return code;
}
