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

#include <stdio.h>
#include <time.h>
#include <sys/stat.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
#ifndef _WIN32
typedef unsigned long DWORD;
typedef unsigned char BYTE;
typedef void *HINSTANCE;
typedef char CHAR;
#endif
typedef unsigned long hCRYPTMSG;
typedef unsigned long hCERTSTORE;
typedef unsigned long HCRYPTPROV;
typedef unsigned long hCERTCOLLECTION;

#define CRT_STORE_PROV_LDAP     0
#define AT_KEYEXCHANGE          1
#define AT_SIGNATURE            2

//Константы для Хранилища
#define STORE_HOST "127.0.0.1"
#define STORE_PORT "62222"

//---------------------------------------------------------------------------

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 int(_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_GetCACertificateKey)
(hCERTSTORE hStore,
	const char *DName,
	const char *keyOID,
	const bool isValid,
	unsigned char *certBody,
	unsigned long *bodySize);

//---------------------------------------------------------------------------
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_GetCACertificateKey    GetCACertificateKey = 0;
HINSTANCE hInstSTRLib = NULL;
//---------------------------------------------------------------------------
int LoadLib()
{
	int ret = 0;
#ifdef _WIN32
	hInstSTRLib = LoadLibraryA(strlib);
#else
	hInstSTRLib = dlopen(strlib, RTLD_LAZY);
#endif
	try
	{
		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;
		GetMYCertificate = (D_GetMYCertificate)GetProcAddress(hInstSTRLib, "GetMYCertificate");
		if (GetMYCertificate == NULL) throw 8;
		CSPCloseContext = (D_CSPCloseContext)GetProcAddress(hInstSTRLib, "CSPCloseContext");
		if (CSPCloseContext == NULL) throw 8;
		GetCACertificateKey = (D_GetCACertificateKey)GetProcAddress(hInstSTRLib, "GetCACertificateKey");
		if (GetCACertificateKey == NULL) throw 9;
	}
	catch (int er) { ret = er; }
	return ret;
}
//---------------------------------------------------------------------------
void lib_free(HINSTANCE Instance)
{
#ifdef _WIN32
	FreeLibrary(Instance);
#else
	dlclose(Instance);
#endif
}
//------------------------------------------------------------------------------
int main(int argc, char* argv[])
{

	int ret = 0;
	int code = 0;
	hCERTSTORE hStore = 0;
	HCRYPTPROV hP = 0;
	unsigned char CertSignBlob[2048];
	unsigned long CertSignSize = 2048;
	unsigned char CertExchBlob[2048];
	unsigned long CertExchSize = 2048;
	char DName[256] = "CN=USER;O=SDK;C=KZ;";
	char Profile[256];

	if (argc<2)
	{
		printf("Specify sign file (ex.[]$ ./getmycert /path/filename.bin [key container])\n");
		return 1;
	}
#ifdef WIND32
	sprintf(Profile, "profile://%s", argv[1]);
#else
	sprintf(Profile, "profile://%s", argv[1]);
#endif
	try
	{
		//Загрузить библиотеку
		code = LoadLib();
		if (code) throw code;
		//Открыть контекст CSP
		code = CSPOpenContext(&hP, (char *)Profile, 25, 0, 0, NULL, 0, NULL, NULL, NULL);
		if (code) throw code;
		// Открыть конекст хранилища
		code = CrtOpenStore(CRT_STORE_PROV_LDAP, hP, 0, false, NULL, &hStore);
		if (code) throw code;
		// Установить параметры хранилища
		// всегде необходимо вызывать перед вызовом GetMYCertificate
		code = CrtSetStorePropertyExt(hStore, 0, DName, STORE_HOST, STORE_PORT, 300, 0, 0);
		if (code) throw code;
		//Получить собственные сертификаты
		code = GetMYCertificate(hStore, DName, AT_SIGNATURE, false, CertSignBlob, &CertSignSize);
		if (code) throw code;
		code = GetMYCertificate(hStore, DName, AT_KEYEXCHANGE, false, CertExchBlob, &CertExchSize);
		if (code) throw code;
		//Если не произошло ошибки, то сертификаты хранятся в CertSignBlob и CertExchBlob соответственно.
		printf("Getting own certificates is done, in CertSignBlobs & CertExchBlob\n");
	}
	catch (int er) { ret = er; }
	if (hStore) { CrtCloseStore(&hStore); hStore = 0; }
	if (hP) { CSPCloseContext(&hP); hP = 0; }
	if (hInstSTRLib) { lib_free(hInstSTRLib); hInstSTRLib = NULL; }
	if (ret != 0) printf("Getting own certificates error [code = %d]\n", ret);
	return ret;
}
//---------------------------------------------------------------------------
