// CrlInfo.cpp : Defines the entry point for the console application.
//
//---------------------------------------------------------------------------
#include <stdio.h>
#include <time.h>
#ifdef _WIN32
#include <windows.h>
#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 TRUE 1
#define FALSE 0
typedef void* HINSTANCE;
typedef unsigned long       DWORD;
typedef char CHAR;
typedef unsigned char       BYTE;
#endif

#define CRYPT_VERIFYCONTEXT     0xF0000000
#define CRYPT_NEWKEYSET         0x00000008
#define CRYPT_DELETEKEYSET      0x00000010
#define CRYPT_MACHINE_KEYSET    0x00000020
#define CRYPT_SILENT            0x00000040
#define CRT_STORE_PROV_LDAP     0
#define RStoreType "t=R;"
#define AStoreType "t=A;"
#define StoreHost "127.0.0.1"
#define StorePort "62222"
#define DN "C=KZ;O=LOCAL;CN=ROOT;"

typedef unsigned long hCERTSTORE;
typedef unsigned long HCRYPTPROV;
//---------------------------------------------------------------------------
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 char* (_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_GetCurrentCRL)
(hCERTSTORE hStore,
	const char *DName,
	unsigned char *crlBody,
	unsigned long *bodySize);
typedef int(_cdecl *D_GetCRLnumber)
(const hCERTSTORE hStore,
	const unsigned char *crlBody,
	const unsigned long bodySize,
	unsigned long *number);
typedef int(_cdecl *D_GetCRLUpDates)
(const hCERTSTORE hStore,
	const unsigned char *crlBody,
	const unsigned long bodySize,
	char *thisUpdate,
	char *nextUpdate);
typedef int(_cdecl *D_GetCRLIssuerInfo)
(const hCERTSTORE hStore,
	const unsigned char *crlBody,
	const unsigned long bodySize,
	char *DName);
typedef int(_cdecl *D_GetCRLDistrPoint)
(const hCERTSTORE hStore,
	const unsigned char *crlBody,
	const unsigned long bodySize,
	char *CApoint);
typedef int(_cdecl *D_GetCRLIssuerNumber)
(const hCERTSTORE hStore,
	const unsigned char *crlBody,
	const unsigned long bodySize,
	unsigned char *serNum,
	unsigned long *numSize);
//---------------------------------------------------------------------------
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_GetCurrentCRL           GetCurrentCRL = 0;
D_GetCRLnumber            GetCRLnumber = 0;
D_GetCRLUpDates           GetCRLUpDates = 0;
D_GetCRLIssuerInfo        GetCRLIssuerInfo = 0;
D_GetCRLDistrPoint        GetCRLDistrPoint = 0;
D_GetCRLIssuerNumber      GetCRLIssuerNumber = 0;
//---------------------------------------------------------------------------
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        LoadLib();
void b2h(unsigned char *inbuf, long  insize, unsigned char *oubuf);
HINSTANCE hInstSTRLib = NULL;
//---------------------------------------------------------------------------
//Получить номер СОСа
int CRLNumber(hCERTSTORE Store, unsigned char *Body, unsigned long Size)
{
	int code, ret = 0;
	unsigned long num;
	if (!Body) return 1;
	try
	{
		code = GetCRLnumber(Store, Body, Size, &num);
		if (code) throw code;
		printf("GetCRLnumber: Current CLR number = %d\n", num);
	}
	catch (int err)
	{
		ret = err;
		printf("%s [GetCRLnumber: error = %d]\n", ErrorString(ret), ret);
	}
	return ret;
}
//---------------------------------------------------------------------------
//Получить время действия СОСа
int CRLUpDates(hCERTSTORE Store, unsigned char *Body, unsigned long Size)
{
	int code, ret = 0;
	char t_date[64], n_date[64];
	if (!Body) return 1;
	try
	{
		code = GetCRLUpDates(Store, Body, Size, t_date, n_date);
		if (code) throw code;
		printf("GetCRLUpDates: thisUpdate = %s\nnextUpdate = %s\n", t_date, n_date);
	}
	catch (int err)
	{
		ret = err;
		printf("%s [GetCRLUpDates: error = %d]\n", ErrorString(ret), ret);
	}
	return ret;
}
//---------------------------------------------------------------------------
//получить информацию о выпустившем CRL
int CRLIssuerInfo(hCERTSTORE Store, unsigned char *Body, unsigned long Size)
{
	int code, ret = 0;
	char DName[256];
	try
	{
		code = GetCRLIssuerInfo(Store, Body, Size, DName);
		if (code) throw code;
		printf("GetCRLIssuerInfo: Issuer = %s\n", DName);
	}
	catch (int err)
	{
		ret = err;
		printf("%s [GetCRLIssuerInfo: error = %d]\n", ErrorString(ret), ret);
	}
	return ret;
}
//---------------------------------------------------------------------------
//Получить адрес УЦ
int CRLDistrPoint(hCERTSTORE *Store, unsigned char *Body, unsigned long Size)
{
	int code, ret = 0;
	char DName[256];
	try
	{
		code = GetCRLDistrPoint(*Store, Body, Size, DName);
		if (code) throw code;
		printf("GetCRLDistrPoint = %s\n", DName);
	}
	catch (int err)
	{
		ret = err;
		printf("%s [GetCRLDistrPoint: error = %d]\n", ErrorString(ret), ret);
	}
	return ret;
}
//---------------------------------------------------------------------------
//получить информацию о серийном номере выпустившего CRL
int CRLIssuerNumber(hCERTSTORE Store, unsigned char *Body, unsigned long Size)
{
	int code, ret = 0, n;
	unsigned char serNum[64];
	unsigned char *hNum;
	unsigned long numSize;
	try
	{
		code = GetCRLIssuerNumber(Store, Body, Size, serNum, &numSize);
		if (code) throw code;
		hNum = (unsigned char*)calloc(numSize * 2 + 1, sizeof(unsigned char));
		b2h(serNum, numSize, hNum);
		n = numSize * 2;
		printf("Serial number = %s\nSerial number len = %d\n", hNum, n);
		if (hNum) free(hNum);
	}
	catch (int err)
	{
		ret = err;
		printf("%s [GetCRLIssuerNumber: error = %d]", ErrorString(ret), ret);
	}
	return ret;
}
//---------------------------------------------------------------------------
int main(int argc, char* argv[])
{
	int ret = 0;
	int code = 0;
	hCERTSTORE hStore = 0;
	HCRYPTPROV hP = 0;
	unsigned char *crlBody = NULL;
	unsigned long bodySize;
	try
	{
		//Загрузить библиотеку
		code = LoadLib();
		if (code)
		{
			printf("[LoadLib: error = %d]\n", code);
			throw code;
		}
		//Открыть контекст CSP без загрузки прфайла
		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(CRT_STORE_PROV_LDAP, hP, 0, false, NULL, &hStore);
		if (code)
		{
			printf("%s [CrtOpenStore: error = %d]\n", ErrorString(code), code);
			throw code;
		}
		// Установить параметры хранилища
		// функцию можно не вызывать, если, например, CRL будет загружен из файла или объявлен константой
		// в этом случае нет необходимости вызывать GetCurrentCRL, можно сразу перейти к получению номера СОСа
		code = CrtSetStorePropertyExt(hStore, 0, RStoreType, StoreHost, StorePort, 300, 0, 0);
		if (code)
		{
			printf("%s [CrtSetStorePropertyExt: error = %d]\n", ErrorString(code), code);
			throw code;
		}
		//Получить текущий СОС
		code = GetCurrentCRL(hStore, DN, crlBody, &bodySize);
		if (code)
		{
			printf("%s [GetCurrentCRL: error = %d]\n", ErrorString(code), code);
			throw code;
		}
		crlBody = (unsigned char*)calloc(bodySize, sizeof(unsigned char));
		memset(crlBody, 0, bodySize);
		code = GetCurrentCRL(hStore, DN, crlBody, &bodySize);
		//Получить номер СОСа
		code = CRLNumber(hStore, crlBody, bodySize);
		//Получить время действия СОСа
		code = CRLUpDates(hStore, crlBody, bodySize);
		//получить информацию о выпустившем CRL
		code = CRLIssuerInfo(hStore, crlBody, bodySize);
		//Получить адрес УЦ
		code = CRLDistrPoint(&hStore, crlBody, bodySize);
		//получить информацию о серийном номере выпустившего CRL
		code = CRLIssuerNumber(hStore, crlBody, bodySize);
		//Если не было ошибки, то отозванные сертификаты хранятся в crlBody соответственно.
	}
	catch (int er) { ret = er; }
	if (crlBody) free(crlBody);
	//закрыть контексты
	if (hStore) { CrtCloseStore(&hStore); hStore = 0; }
	if (hP) { CSPCloseContext(&hP); hP = 0; }
	if (hInstSTRLib) { lib_free(hInstSTRLib); hInstSTRLib = NULL; }
	return ret;
}
//---------------------------------------------------------------------------
int LoadLib()
{
	int ret = 0;
	try
	{
		hInstSTRLib = load_lib(strlib);
		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;
		CSPCloseContext = (D_CSPCloseContext)GetProcAddress(hInstSTRLib, "CSPCloseContext");
		if (CSPCloseContext == NULL) throw 8;
		GetCurrentCRL = (D_GetCurrentCRL)GetProcAddress(hInstSTRLib, "GetCurrentCRL");
		if (GetCurrentCRL == NULL) throw 9;
		GetCRLnumber = (D_GetCRLnumber)GetProcAddress(hInstSTRLib, "GetCRLnumber");
		if (GetCRLnumber == NULL) throw 10;
		GetCRLUpDates = (D_GetCRLUpDates)GetProcAddress(hInstSTRLib, "GetCRLUpDates");
		if (GetCRLUpDates == NULL) throw 11;
		GetCRLIssuerInfo = (D_GetCRLIssuerInfo)GetProcAddress(hInstSTRLib, "GetCRLIssuerInfo");
		if (GetCRLIssuerInfo == NULL) throw 12;
		GetCRLDistrPoint = (D_GetCRLDistrPoint)GetProcAddress(hInstSTRLib, "GetCRLDistrPoint");
		if (GetCRLDistrPoint == NULL) throw 13;
		GetCRLIssuerNumber = (D_GetCRLIssuerNumber)GetProcAddress(hInstSTRLib, "GetCRLIssuerNumber");
		if (GetCRLIssuerNumber == NULL) throw 14;
	}
	catch (int er) { ret = er; }
	return ret;
}
//---------------------------------------------------------------------------
void b2h(unsigned char *inbuf, long  insize, unsigned char *oubuf)
{
	char *HAlf = "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];
	}
}
//---------------------------------------------------------------------------
