// CertInfo.cpp : Defines the entry point for the console application.
//
#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.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 CERTIFICATE "MIIEMjCCA5qgAwIBAgIUHFtJDkujVVDhRbdQfB5yeYMi+7kwDgYKKoMOAwoBAQID\
					AgUAMIHxMQswCQYDVQQGEwJLWjGBwzCBwAYDVQQKDIG40JDQutGG0LjQvtC90LXR\
					gNC90L7QtSDQvtCx0YnQtdGB0YLQstC+ICLQndCw0YbQuNC+0L3QsNC70YzQvdCw\
					0Y8g0L/Qu9Cw0YLRkdC20L3QsNGPINC60L7RgNC/0L7RgNCw0YbQuNGPIiDQndCw\
					0YbQuNC+0L3QsNC70YzQvdC+0LPQviDQkdCw0L3QutCwINCg0LXRgdC/0YPQsdC7\
					0LjQutC4INCa0LDQt9Cw0YXRgdGC0LDQvTEcMBoGA1UEAwwT0KPQpiAyINGD0YDQ\
					vtCy0L3RjzAeFw0yNDEyMTIwNzMzNDhaFw0yNTEyMTIwNzM4NDhaMCoxCzAJBgNV\
					BAYTAktaMQwwCgYDVQQKEwNTREsxDTALBgNVBAMTBFVTRVIwgawwIwYJKoMOAwoB\
					AQICMBYGCiqDDgMKAQECAgEGCCqDDgMKAQMDA4GEAASBgPmmzl6n+1hyj3B2ecQ1\
					DmvF6OMm27gwaVE5g1t968Om2X/8ZuAsM+hXywWgFaQk/1gYs6QArT9plmhYio57\
					vG9/8sIhuHWUHDbZZL+6dngT7SuMnM+x0Y0S8EreYNOQeSnHtQumLqJVESF7WLiZ\
					h+/LV2D2jGZF1YghoEZ19Umyo4IBfDCCAXgwCwYDVR0PBAQDAgbAMBMGA1UdJQQM\
					MAoGCCsGAQUFBwMEMB0GA1UdDgQWBBQcW0kOS6NVUOFFt1B8HnJ5gyL7uTCCATMG\
					A1UdIwSCASowggEmgBRCy5rn4q9zCLEbMC0dv93F12WUH6GB96SB9DCB8TELMAkG\
					A1UEBhMCS1oxgcMwgcAGA1UECgyBuNCQ0LrRhtC40L7QvdC10YDQvdC+0LUg0L7Q\
					sdGJ0LXRgdGC0LLQviAi0J3QsNGG0LjQvtC90LDQu9GM0L3QsNGPINC/0LvQsNGC\
					0ZHQttC90LDRjyDQutC+0YDQv9C+0YDQsNGG0LjRjyIg0J3QsNGG0LjQvtC90LDQ\
					u9GM0L3QvtCz0L4g0JHQsNC90LrQsCDQoNC10YHQv9GD0LHQu9C40LrQuCDQmtCw\
					0LfQsNGF0YHRgtCw0L0xHDAaBgNVBAMME9Cj0KYgMiDRg9GA0L7QstC90Y+CFELL\
					mufir3MIsRswLR2/3cXXZZQfMA4GCiqDDgMKAQECAwIFAAOBgQAmdybSJ7VFQ2NZ\
					anXSOpVu2DMh9Er8JIDCXJUn13/rdwr4AxNgyGa25NgANY5LeWUlD61KtRGs126I\
					af0S2HPu8Fy06FnOjCrjD8SLKUnJJ4tShXksagCltNP+etn4vttPdThl8Ara8PDB\
					Ja+nKvEYk2JpI0hki9kCNXEx3DOQEA=="


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;
}
