/*
 * Copyright(C) 2000-2010 Проект ИОК
 *
 * Этот файл содержит информацию, являющуюся
 * собственностью компании Крипто Про.
 *
 * Любая часть этого файла не может быть скопирована,
 * исправлена, переведена на другие языки,
 * локализована или модифицирована любым способом,
 * откомпилирована, передана по сети с или на
 * любую компьютерную систему без предварительного
 * заключения соглашения с компанией Крипто Про.
 *
 * Программный код, содержащийся в этом файле, предназначен
 * исключительно для целей обучения и не может быть использован
 * для защиты информации.
 *
 * Компания Крипто-Про не несет никакой
 * ответственности за функционирование этого кода.
 */


#include <stdio.h>
#ifdef _WIN32
#include <windows.h>
#include <wincrypt.h>
#include <wincryptex.h>
#else
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <WinCryptEx.h>
#endif	// _WIN32
#include "UnixEnroll.h"
#define TYPE_DER (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING)


// Начало примера (не следует удалять данный комментарий, он используется 
// для автоматической сборки документации)
//----------------------------------------------------------------------
// Пример кода для установки сертификата. В качестве параметра передается 
// файл сертификата, который может быть получен вызовом 
// /opt/cprocsp/src/samples/CSP/MSCA 
//----------------------------------------------------------------------


static void HandleError(const char *s);
#ifdef _WIN32
#   define CONTAINER L"test"
#else
#   define CONTAINER L"\\\\.\\HDIMAGE\\test"
#endif

class Callbacks: public UnixEnroll::UserCallbacks
{
public:
	bool askPermissionToAddToRootStore( const BYTE* pbCert, DWORD cbCert, bool force = false) const;
	UserCallbacks* clone() const;
	virtual ~Callbacks() {}
};

//--------------------------------------------------------------------
// Функция askPermissionToAddToRootStore всегда будет разрешать 
// записывать сертификат в корневое хранилище

bool Callbacks::askPermissionToAddToRootStore( const BYTE* pbCert, DWORD cbCert, bool) const
{

  	int res;
	DWORD size = 0;
	PBYTE pHashValue = NULL;
	res = CryptHashCertificate(0, 0, 0, pbCert, cbCert, NULL, &size);
	if(!res) {
	    return GetLastError();
	}
	
	pHashValue =(BYTE *)malloc(size);
	if(!pHashValue) {
	    return GetLastError();
	}
	
	res = CryptHashCertificate(0, 0, 0, pbCert, cbCert, pHashValue, &size);
	if(!res) {
	    free(pHashValue);
	    return GetLastError();
	}
	
	return true;
}

UnixEnroll::UserCallbacks* Callbacks::clone() const
{
	return new Callbacks();
}


//  В этом примере используется функция HandleError, функция обработки
//  простых ошибок, для печати сообщения об ошибке в стандартный файл 
//  ошибок (stderr) и выхода из программы. 
//  В большинстве приложений эта функция заменяется другой функцией, 
//  которая выводит более полное сообщение об ошибке.

void HandleError(const char *s){
	DWORD err = GetLastError();
	printf("Error number     : 0x%x\n", err);
	printf("Error description: %s\n", s);
	if(!err) err = 1;
	exit(err);
} 	

static long InstallCert(BSTR bstrData){
	HRESULT res = -1;
	Callbacks tb;
	UnixEnroll * pEnroll =  new UnixEnroll(tb,false);
	const char * StoreName = "My";
	LONG StoreType=CERT_SYSTEM_STORE_CURRENT_USER;

	//  put_CAStoreFlags задает хранилище промежуточных УЦ и флаги его 
	//  открытия
	pEnroll->put_CAStoreFlags(StoreType);
	// put_MyStoreFlags задает хранилище сертификатов пользователя и флаги его открытия.
	pEnroll->put_MyStoreFlags(StoreType);
	// put_RootStoreFlags задает доверенное хранилище корневых сертификатов и флаги его открытия.
	pEnroll->put_RootStoreFlags(StoreType);
	// put_RequestStoreFlags задает хранилище запроса и флаги его открытия.
	pEnroll->put_RequestStoreFlags(StoreType);
	// put_MyStoreName задает имя хранилища сертификатов пользователя
	pEnroll->put_MyStoreName(ConvertStringToBSTR(StoreName));
	// put_ProviderType задает тип CSP для создания ключа.
	pEnroll->put_ProviderType(PROV_GOST_2001_DH);
	//  put_DeleteRequestCert показывает нужно ли удалять псевдосертификат 
	// в хранилище запросов на сертификат
	pEnroll->put_DeleteRequestCert(TRUE);
        
	// Обработка PKCS#7 ответа от УЦ.
	res = pEnroll->acceptPKCS7(bstrData);
    	
	delete pEnroll;
	return res;
} // Конец опредления InstallCert



int main(int argc, char* argv[]){
	FILE* fileCert; 
	BSTR bstrData;
	std::string str;
	int c;
	HRESULT res;
	if (argc == 2)
	    fileCert = fopen(argv[1],"rb");
	else
	    if ((fileCert = fopen("certificate.cer", "rb")) == NULL){
		HandleError( "Error open file.");
		return 1;
	    }
	    
	while ( (c = fgetc(fileCert)) != EOF ){
		str = str + (char)c;
	}
	
	printf("cert = %s \n\n", str.c_str());
	bstrData = ConvertStringToBSTR(str.c_str());	
	
	res = InstallCert(bstrData);
	
	if (res != S_OK){
		SysFreeString(bstrData);
		fclose(fileCert);
		HandleError( "Error installing certificate.");
	} else {
		printf("Successful installing certificate. \n");
	}
	
	SysFreeString(bstrData);
	fclose(fileCert);
	
	return 0;
}//end of main



//END-OF-FILE
