// CertRevokeRequest.cpp : Defines the entry point for the console application.
//

#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.so.1.0"
#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;
}
