// CertByDN.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 STORE_HOST "127.0.0.1"
#define STORE_PORT "62222"

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 *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 *errorstring) (const int err);
typedef int(_cdecl *getnamecertificate)
(hCERTSTORE hStore,
	const char *DName,
	const char *keyOID,
	const bool isValid,
	const bool isRevoked,
	unsigned char *certBody,
	unsigned long *bodySize,
	char* fname);

cspopencontext         CSPOpenContext;
crtopenstore           CrtOpenStore;
crtclosestore          CrtCloseStore;
cspclosecontext        CSPCloseContext;
crtsetstorepropertyext CrtSetStorePropertyExt;
getnamecertificate     GetNameCertificate;
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;
	}
	CrtSetStorePropertyExt = (crtsetstorepropertyext)GetProcAddress(lib, "CrtSetStorePropertyExt");
	if (!CrtSetStorePropertyExt)
	{
		printf("error load function - %s", "CrtSetStorePropertyExt");
		return 1;
	}
	GetNameCertificate = (getnamecertificate)GetProcAddress(lib, "GetNameCertificate");
	if (!GetNameCertificate)
	{
		printf("error load function - %s", "GetNameCertificate");
		return 1;
	}
	ErrorString = (errorstring)GetProcAddress(lib, "ErrorString");
	if (!ErrorString)
	{
		printf("error load function - %s", "ErrorString");
		return 1;
	}
	return 0;
}
//------------------------------------------------------------------------------
int main(void)
{
	HINSTANCE        lib = NULL;
	int 				ret = 0;
	int 				code = 0;
	HCRYPTPROV 		hP = 0;
	hCERTSTORE 		hStore = (hCERTSTORE)0;
	unsigned char 	*CertSignBlob = NULL;
	unsigned long 	CertSignSize = 0;
	char DName[] = "CN=USER;O=SDK;C=KZ;";
	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("CSPOpenContext, Error = %d (%s)\n", code, ErrorString(code));
			throw code;
		}
		// Открыть конекст хранилища :
		code = CrtOpenStore(0, hP, 0, false, NULL, &hStore);
		if (code)
		{
			printf("CrtOpenStore, Error = %d (%s)\n", code, ErrorString(code));
			throw code;
		}
		// Настроить хранилище сертификатов (обязательно, так как следующbt функциb обращаются к LDAP-хранилищу):
		code = CrtSetStorePropertyExt(hStore, 0, "t=L;", STORE_HOST, STORE_PORT, 300, "", "");
		if (code)
		{
			printf("CrtSetStorePropertyExt, Error = %d (%s)\n", code, ErrorString(code));
			throw code;
		}
		//Получить размер сертификата пользователя
		code = GetNameCertificate(hStore, DName, "1.2.398.3.10.1.1.2.2", true, false, NULL, &CertSignSize, NULL);
		if (code)
		{
			printf("GetNameCertificate, Error = %d (%s)\n", code, ErrorString(code));
			throw code;
		}
		CertSignBlob = new unsigned char[CertSignSize];
		// Получить сертификат пользователя
		code = GetNameCertificate(hStore, DName, "1.2.398.3.10.1.1.2.2", true, false, CertSignBlob, &CertSignSize, NULL);
		if (code)
		{
			printf("GetNameCertificate, Error = %d (%s)\n", code, ErrorString(code));
			throw code;
		}
		printf("Certificate was found, size = %d\n", CertSignSize);
		// Если не было ошибки, то сертификат хранится в CertSignBlob.
	}
	catch (int er)
	{
		ret = er;
	}
	if (CertSignBlob) delete[] CertSignBlob;
	// Освободить контекст хранилища :
	if (hStore)
	{
		CrtCloseStore(&hStore);
		hStore = (hCERTSTORE)0;
	}
	// Освободить контекст криптопровайдера :
	if (hP)
	{
		CSPCloseContext(&hP);
		hP = (HCRYPTPROV)0;
	}
	if (lib) lib_free(lib);
	return ret;
}
//-----------------------------------------------------------------------
