//==========< HISTORY >=============================
//      29.10.2003  Changes by AA
//                  ReadCertFromCard adapted
//                  from Tarmo's example
//      09.10.2003  Changes by AA
//      02.09.2003  Changes from Tarmo Milva
//Changed functions:
//DigiCrypt_GetDataFromCert
//DigiCrypt_GetFirstAllowedCSPName
//DigiCrypt_GetDefaultKeyContainerName
//DigiCrypt_SelectFromAllKeysCerts
//
#include "DigiCrypt.h"
#include "DigiDocDefs.h"
#include "DigiDocConfig.h"
#include <stdio.h>
#include <tchar.h>

#define MY_ENCODING_TYPE  (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)

#define dSTRING_ITEM_LEN  255
#define dNAME_ITEM_LEN   1024
#define dCSPTYPE_NOTDEFINED -1

static char *psData_CSP_Path = "SOFTWARE\\Microsoft\\Cryptography\\Defaults\\Provider\\";
static char *psData_Extra_CSP_Name = "Advanced Setec SetCSP";
static char *psData_Ignore_CSP_Name ="XXXEstEID";
static char *psData_Est_CSP_Name = "EstEID";

//Global data
static HCRYPTPROV oG_hProvider = 0;
static char  oG_sCSPName[dSTRING_ITEM_LEN+1];
static char  oG_sKeyContainerName[dNAME_ITEM_LEN+1];
static BOOL  oG_fDialogUserCancel;

extern int RunDialogUnit(char *psList[], int iWinWidth, int iWinHeight);
       PCCERT_CONTEXT DigiCrypt_ReadCertFromCard(void);
static BOOL DigiCrypt_AddCertToStore(PCCERT_CONTEXT pCert);

static BOOL OpenProvider(HCRYPTPROV *phProv, char *psProvider, DWORD dwFlags);
static HCERTSTORE DigiCrypt_OpenStore(void);
static char *DigiCrypt_GetFirstAllowedCSPNameNew(void);
static char *DigiCrypt_GetFirstAllowedCSPName(void);
static void  DigiCrypt_ReleaseFirstAllowedCSP(void);
static BOOL  DigiCrypt_GetCSPFromCert(PCCERT_CONTEXT  pCertContext, char *psResult, int iMaxResLen);
static BOOL  DigiCrypt_GetContainerFromCert(PCCERT_CONTEXT  pCertContext, char *psResult, int iMaxResLen);
static BOOL  DigiCrypt_CertIsSig(PCCERT_CONTEXT  pCertContext);

static char *DigiCrypt_GetDefaultKeyContainerName(char *psCSPName);
static char *DigiCrypt_GetDefaultKeyContainerNameSimple(char *psCSPName);
static char *DigiCrypt_GetDefaultCSPName(void);
static BOOL  DigiCrypt_GetDataFromCert(PCCERT_CONTEXT  pCertContext);
static PCCERT_CONTEXT  DigiCrypt_SelectFromAllCerts(void);
static PCCERT_CONTEXT  DigiCrypt_SelectFromAllKeysCerts(HCRYPTPROV hProvider);
static void            DigiCrypt_SelectCertsFromKeyContainer(HCRYPTPROV hProv, char *psContainerName);
static void            DigiCrypt_ChangeContainerName(char *psContainerName);

static void            RunDlg_Clear(void);
static BOOL            RunDlg_AddItem(PCCERT_CONTEXT  pCertContext, BOOL fTimeCheck);
static PCCERT_CONTEXT  RunDlg_RunDlg(void);
static BOOL            RunDlg_FillItem(PCCERT_CONTEXT  pCertContext, char *psRes, int len);

static void IntLogToFile(char *psMsg, int iMsgLen);
static BOOL IsLogEnabled(void);

PCCERT_CONTEXT  DigiCrypt_FindContext(BOOL fByKeyContainer, DWORD *dwResult)
{
  PCCERT_CONTEXT hCert = NULL;
  char *psCSPName;
  char *psDefaultKeyContainerName;
  oG_fDialogUserCancel = FALSE;

  *dwResult = dDigiCrypt_Okey;
  memset(oG_sCSPName, 0, sizeof(oG_sCSPName));
  memset(oG_sKeyContainerName, 0, sizeof(oG_sKeyContainerName));

  if (fByKeyContainer == TRUE)  {  
    hCert = DigiCrypt_ReadCertFromCard();
    //TEST
    //Test_ReadCertDataC(hCert);
    //ENDTEST
    if (hCert == NULL) {
      psCSPName = DigiCrypt_GetFirstAllowedCSPNameNew();
      if (psCSPName == NULL)
	*dwResult = dDigiCrypt_Error_NotFoundCSP;
      else {
	psDefaultKeyContainerName = DigiCrypt_GetDefaultKeyContainerName(oG_sCSPName);
	if (psDefaultKeyContainerName == NULL)
	  *dwResult = dDigiCrypt_Error_NoDefaultKey;
	else
	  hCert = DigiCrypt_SelectFromAllKeysCerts(oG_hProvider);
      }
    }
  } else {
    hCert = DigiCrypt_SelectFromAllCerts();
    if (hCert != NULL)
      DigiCrypt_GetDataFromCert(hCert);
  }
  if (hCert == NULL) {
    if (oG_fDialogUserCancel == TRUE)
      *dwResult = dDigiCrypt_Error_UserCancel;
    else {
      if (*dwResult == dDigiCrypt_Okey) 
	*dwResult = dDIgiCrypt_Error_NotFoundCert;
    }
  }
  return(hCert); 
}

PCCERT_CONTEXT DigiCrypt_ReadCertFromCard(void)
{
HCRYPTPROV hCryptProv;
BYTE       *pbData = NULL;   
HCRYPTKEY  hKey;          
DWORD cbData = 0;
DWORD dwKeyType=0, dwKeySpec = AT_SIGNATURE;
DWORD dwErrCode=0;
DWORD cspType=0;
DWORD cspFlag=CRYPT_SILENT;
char *psCspName = NULL;
char *psKeyContainer;
BOOL fRes = FALSE;
PCCERT_CONTEXT  pCertContext = NULL; 
CRYPT_KEY_PROV_INFO KeyProvInfo;
LPWSTR wszContainerName=NULL;
LPWSTR wszProvName=NULL;
DWORD cchContainerName;
DWORD cchCSPName;
HCRYPTPROV hProv;


DigiCrypt_ReleaseFirstAllowedCSP();

psCspName=DigiCrypt_GetFirstAllowedCSPNameNew();

//very dummy thing.. i check from csp creators why i should do so...
if(!lstrcmp(psCspName,"EstEID Card CSP"))
   fRes = CryptAcquireContext(&hProv,"XXX",psCspName,2, CRYPT_SILENT);
// end dummy//

if (psCspName == NULL || strstr(psCspName,psData_Est_CSP_Name) == NULL)
  return(pCertContext);

cspType=DigiCrypt_FindContext_GetCSPType(psCspName);

psKeyContainer=DigiCrypt_GetDefaultKeyContainerName(psCspName);

fRes = CryptAcquireContext(&hCryptProv,psKeyContainer,psCspName,cspType, CRYPT_SILENT);
if (fRes == FALSE)
  return(pCertContext);

// VS: use alsu auth keys if KEY_USAGE_CHECK=false
dwKeySpec = ConfigItem_lookup_int("KEY_USAGE_CHECK", 1) ? AT_SIGNATURE : 0;

fRes=CryptGetUserKey(hCryptProv, dwKeySpec, &hKey);
if (fRes == TRUE)
  {
  fRes=CryptGetKeyParam(hKey, KP_CERTIFICATE, NULL, &cbData, 0);
  if (fRes == TRUE)
    {
    pbData = malloc(cbData);
    if (pbData == NULL)
      fRes = FALSE;
    }
  if (fRes == TRUE)
    fRes=CryptGetKeyParam(hKey, KP_CERTIFICATE, pbData, &cbData, 0);
  if (fRes == TRUE)
    {
    pCertContext = CertCreateCertificateContext(MY_ENCODING_TYPE,pbData,cbData);
    if (pCertContext != NULL)
      { 
	  wszContainerName=NULL;
	  wszProvName=NULL;
	  cchContainerName = (lstrlen(psKeyContainer) + 1)  * sizeof(WCHAR);
	  cchCSPName = (lstrlen(psCspName) + 1) * sizeof(WCHAR);
      wszContainerName = (LPWSTR) malloc(cchContainerName);
      wszProvName = (LPWSTR) malloc(cchCSPName);
      mbstowcs(wszContainerName, psKeyContainer,cchContainerName);
	  mbstowcs(wszProvName, psCspName, cchCSPName);
      ZeroMemory((PVOID)&KeyProvInfo, sizeof(CRYPT_KEY_PROV_INFO));
      KeyProvInfo.pwszContainerName = (LPWSTR) wszContainerName;
      KeyProvInfo.pwszProvName      = (LPWSTR) wszProvName;
      KeyProvInfo.dwProvType        = PROV_RSA_SIG;
      KeyProvInfo.dwFlags           = 0;
      KeyProvInfo.dwKeySpec         = dwKeyType;
      fRes = CertSetCertificateContextProperty(pCertContext,CERT_KEY_PROV_INFO_PROP_ID, 0, (const void *) &KeyProvInfo);
      if (wszContainerName != NULL)
        free(wszContainerName);
      if (wszProvName != NULL)
        free(wszProvName);

      }
    }
  }

//if (pCertContext != NULL)
//  DigiCrypt_AddCertToStore(pCertContext);
if (fRes == FALSE && pCertContext != NULL)
  {
  CertFreeCertificateContext(pCertContext);
  pCertContext = NULL;
  }
if (pbData != NULL)
  free(pbData);
if (hCryptProv != 0)
  CryptReleaseContext(hCryptProv, 0);
return(pCertContext);
}


static BOOL DigiCrypt_AddCertToStore(PCCERT_CONTEXT pCert)
{
BOOL fRes = FALSE;
HCERTSTORE  hSystemStore = NULL;  // The system store handle.
if (pCert != NULL)
  {
  if (hSystemStore = CertOpenStore(
     CERT_STORE_PROV_SYSTEM_A, 
     0,                   // Encoding type not needed with this PROV.
     0,                   // Accept the default HCRYPTPROV. 
     CERT_STORE_NO_CRYPT_RELEASE_FLAG |
     CERT_SYSTEM_STORE_CURRENT_USER,"MY"))
    {
    if (CertAddCertificateContextToStore(hSystemStore, pCert, CERT_STORE_ADD_REPLACE_EXISTING,NULL))
      fRes = TRUE;
    }
  }
if (hSystemStore != NULL)
  CertCloseStore(hSystemStore, CERT_CLOSE_STORE_CHECK_FLAG);
return(fRes);
}


char *DigiCrypt_FindContext_GetKeyName()
{
 if (lstrlen(oG_sKeyContainerName) > 0)
   return(oG_sKeyContainerName);
 else
  return(NULL);
}

char *DigiCrypt_FindContext_GetCSPName()
{
 if (lstrlen(oG_sCSPName) > 0)
   return(oG_sCSPName);
 else
  return(NULL);
}

DWORD DigiCrypt_FindContext_GetCSPType(char *psCSPName)
{
  DWORD dwRes = PROV_RSA_SIG;
  DWORD dwType = REG_DWORD;
  DWORD dwLen  = dSTRING_ITEM_LEN;
  DWORD *pdwVal;
  HKEY hKey;
  LONG lRes;
  char sKeyNameBuf[dSTRING_ITEM_LEN+1];
  char sValue[dSTRING_ITEM_LEN+1];

  strncpy(sKeyNameBuf, psData_CSP_Path, sizeof(sKeyNameBuf));
  strncat(sKeyNameBuf, psCSPName, sizeof(sKeyNameBuf) - strlen(sKeyNameBuf));
  lRes = RegOpenKeyEx(HKEY_LOCAL_MACHINE,sKeyNameBuf, 0, KEY_READ, &hKey);
  if (lRes == ERROR_SUCCESS) {
    lRes = RegQueryValueEx(hKey, "Type", 0, &dwType, (LPBYTE)sValue, &dwLen);
    if (lRes == ERROR_SUCCESS) {
      pdwVal = (DWORD *)sValue;
      dwRes = (*pdwVal);
    }
    RegCloseKey(hKey);
  }
  return(dwRes);
}

static BOOL OpenProvider(HCRYPTPROV *phProv, char *psProvider, DWORD dwFlags)
{
  BOOL fRes;
  DWORD dwType = DigiCrypt_FindContext_GetCSPType(psProvider);
  fRes = CryptAcquireContext(phProv,NULL,psProvider, dwType, dwFlags);
  return(fRes);
}

static HCERTSTORE DigiCrypt_OpenStore(void)
{
HCERTSTORE hStore;
hStore = CertOpenStore(CERT_STORE_PROV_SYSTEM,0,(HCRYPTPROV)NULL,CERT_SYSTEM_STORE_CURRENT_USER,L"MY");
return(hStore);
}


static BOOL DigiCrypt_GetCSPFromCert(PCCERT_CONTEXT  pCertContext, char *psResult, int iMaxResLen)
{
BOOL  fRes = FALSE;
CRYPT_KEY_PROV_INFO *poKeyInfo;
DWORD pcbData;
DWORD dwLen;
if (pCertContext == NULL || psResult == 0)
  return(fRes);
fRes = CertGetCertificateContextProperty(pCertContext,CERT_KEY_PROV_INFO_PROP_ID,NULL,&pcbData);
if (fRes == TRUE)
  {
  poKeyInfo = malloc(pcbData);
  if (poKeyInfo != NULL)
    {
    fRes = CertGetCertificateContextProperty(pCertContext,CERT_KEY_PROV_INFO_PROP_ID,poKeyInfo,&pcbData);
	  if (fRes == TRUE)
	    {
      if (poKeyInfo->pwszProvName != NULL)
	      {
        dwLen = WideCharToMultiByte(CP_ACP,0,poKeyInfo->pwszProvName,-1,psResult,iMaxResLen,NULL,NULL);
		    }
	    else
		    fRes = FALSE;
	    }
    free(poKeyInfo);
    }
  }
return(fRes);
}

static BOOL DigiCrypt_GetContainerFromCert(PCCERT_CONTEXT  pCertContext, char *psResult, int iMaxResLen)
{
BOOL  fRes = FALSE;
CRYPT_KEY_PROV_INFO *poKeyInfo;
DWORD pcbData;
DWORD dwLen;
if (pCertContext == NULL || psResult == 0)
  return(fRes);
fRes = CertGetCertificateContextProperty(pCertContext,CERT_KEY_PROV_INFO_PROP_ID,NULL,&pcbData);
if (fRes == TRUE)
  {
  poKeyInfo = malloc(pcbData);
  if (poKeyInfo != NULL)
    {
    fRes = CertGetCertificateContextProperty(pCertContext,CERT_KEY_PROV_INFO_PROP_ID,poKeyInfo,&pcbData);
	  if (fRes == TRUE)
	    {
      if (poKeyInfo->pwszContainerName != NULL)
	      {
        
			  dwLen = WideCharToMultiByte(CP_ACP,0,poKeyInfo->pwszContainerName,-1,psResult,iMaxResLen,NULL,NULL);
		    }
	    else
		    fRes = FALSE;
	    }
    free(poKeyInfo);
    }
  }
return(fRes);
}

static BOOL DigiCrypt_CertIsSig(PCCERT_CONTEXT  pCertContext)
{
BOOL  fRes = FALSE;
CRYPT_KEY_PROV_INFO *poKeyInfo;
DWORD pcbData;
if (pCertContext == NULL)
  return(fRes);
fRes = CertGetCertificateContextProperty(pCertContext,CERT_KEY_PROV_INFO_PROP_ID,NULL,&pcbData);
if (fRes == TRUE)
  {
  poKeyInfo = malloc(pcbData);
  if (poKeyInfo != NULL)
    {
    fRes = CertGetCertificateContextProperty(pCertContext,CERT_KEY_PROV_INFO_PROP_ID,poKeyInfo,&pcbData);
	if (fRes == TRUE)
	  {
      if (poKeyInfo->dwProvType == PROV_RSA_SIG)
        fRes = TRUE;
	  }
    free(poKeyInfo);
    }
  }
return(fRes);
}


static BOOL DigiCrypt_GetDataFromCert(PCCERT_CONTEXT  pCertContext)
{
  BOOL  fRes = FALSE;
  char sContainer[dNAME_ITEM_LEN+1];
  //DWORD dwLen;
  if (pCertContext == NULL)
    return(fRes);
  fRes = DigiCrypt_GetCSPFromCert(pCertContext, oG_sCSPName,dSTRING_ITEM_LEN);

  if (fRes == TRUE) {
    //  DigiCrypt_GetDefaultKeyContainerNameSimple(oG_sCSPName);  //this is not usable. Tarmo changed that! Instead we should use the following:
    if (DigiCrypt_GetContainerFromCert(pCertContext, sContainer, dNAME_ITEM_LEN) == TRUE) {
      strncpy(oG_sKeyContainerName, sContainer, sizeof(oG_sKeyContainerName));   
    }
  }
  return(fRes);
}

static char *DigiCrypt_GetFirstAllowedCSPNameNew(void)
{
  char *psRes = NULL;
  HKEY  hKey = NULL;
  LONG  lRet=0;
  DWORD dwIndex = 0;
  BOOL  fRes;
  char sProvName[dSTRING_ITEM_LEN+1];
  char sKeyNameBuf[dSTRING_ITEM_LEN+1];
  HCRYPTPROV hProvide = 0;
  DWORD dwBufLen;
  FILETIME oTime;
  //char buff[200];
  BYTE pbData[dNAME_ITEM_LEN+1];
  DWORD cbData=dNAME_ITEM_LEN+1;
  //
  DWORD dwProvType;

  strncpy(sKeyNameBuf, psData_CSP_Path, sizeof(sKeyNameBuf));
  lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,sKeyNameBuf,0, KEY_READ, &hKey);

  while (lRet == ERROR_SUCCESS)  {
    dwBufLen = dSTRING_ITEM_LEN;
    lRet = RegEnumKeyEx(hKey,dwIndex,sProvName,&dwBufLen,NULL,NULL,0,&oTime);
    if (lRet == ERROR_SUCCESS) {
      if (lstrcmp(sProvName,psData_Ignore_CSP_Name) != 0) {
	dwProvType = DigiCrypt_FindContext_GetCSPType(sProvName);
	LOG("CSP %s",sProvName);
	//printf("%s :",sProvName);
	if ((lstrcmp(sProvName,psData_Extra_CSP_Name) != 0) && (lstrcmp(sProvName,"Belgium Identity Card CSP")!=0)) {
        //fRes = OpenProvider(&hProvide, sProvName, CRYPT_SILENT);
	  fRes = CryptAcquireContext(&hProvide,NULL,sProvName,dwProvType, CRYPT_SILENT);
	  fRes=CryptGetProvParam(hProvide, PP_ENUMCONTAINERS, pbData, &cbData,CRYPT_FIRST);
	  //	  printf("X\n");
	} else {
	  //fRes = OpenProvider(&hProvide, sProvName, CRYPT_VERIFYCONTEXT);
	  //fRes = CryptAcquireContext(&hProvide,"SetCARDKeyContainer",sProvName,dwProvType, CRYPT_SILENT);
	  fRes = CryptAcquireContext(&hProvide,NULL,sProvName,dwProvType, CRYPT_VERIFYCONTEXT);
	  if (fRes == TRUE) {
	    //the extra csp might give wrong answer. We should ask from provider, why.
	    //The following is the work-around -- try to lookup key container from the card.
	    //if the result is negative this is a not the csp what is needed.
     	    fRes=CryptGetProvParam(hProvide, PP_ENUMCONTAINERS, pbData, &cbData,CRYPT_FIRST);
	    if (fRes == TRUE)
	      fRes=CryptAcquireContext(&hProvide,(char*)pbData,sProvName,dwProvType, CRYPT_SILENT);
	  }
	}
	//printf("fRes: %x\n",GetLastError());
	if (fRes == TRUE) { // && dwProvType == 2) 
	  //  printf("OK %d %s\n",cbData, pbData);
	  //set global values
	  LOG("CSP %s accepted",sProvName);
	  //is it hardware token?
	  cbData=dNAME_ITEM_LEN+1;
	  if (CryptGetProvParam(hProvide, PP_IMPTYPE, pbData, &cbData, 0)) {
	    //printf("implementat: %d\n",pbData[0]);
	    if((pbData[0] & 1))  // hardware token
	      {
		strncpy(oG_sCSPName, sProvName, sizeof(oG_sCSPName));
		//CryptReleaseContext(hProvide, 0);
		psRes = oG_sCSPName;
		break;
	      }
	  }
	}
      }
    }
    //hProvide = 0;
    CryptReleaseContext(hProvide, 0);
    dwIndex++;
  }
  if (hKey != NULL)
    RegCloseKey(hKey);
  return(psRes);
}


static char *DigiCrypt_GetFirstAllowedCSPName(void)
{
  char *psRes = NULL;
  HKEY  hKey = NULL;
  LONG  lRet=0;
  DWORD dwIndex = 0;
  BOOL  fRes;
  char sProvName[dSTRING_ITEM_LEN+1];
  char sKeyNameBuf[dSTRING_ITEM_LEN+1];
  HCRYPTPROV hProvide = 0;
  DWORD dwBufLen;
  FILETIME oTime;
  //char buff[200];
  BYTE pbData[dNAME_ITEM_LEN+1];
  DWORD cbData=dNAME_ITEM_LEN+1;
  DWORD dwProvType;

  strncpy(sKeyNameBuf, psData_CSP_Path, sizeof(sKeyNameBuf));
  lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,sKeyNameBuf,0, KEY_READ, &hKey);
  while (lRet == ERROR_SUCCESS) {
    dwBufLen = dSTRING_ITEM_LEN;
    lRet = RegEnumKeyEx(hKey,dwIndex,sProvName,&dwBufLen,NULL,NULL,0,&oTime);
    if (lRet == ERROR_SUCCESS)    {
      if (lstrcmp(sProvName,psData_Ignore_CSP_Name) != 0) {
	dwProvType = DigiCrypt_FindContext_GetCSPType(sProvName);
	LOG("CSP %s",sProvName);
	if (lstrcmp(sProvName,psData_Extra_CSP_Name) != 0)
          fRes = OpenProvider(&hProvide, sProvName, CRYPT_SILENT);
	else {
	  fRes = OpenProvider(&hProvide, sProvName, CRYPT_VERIFYCONTEXT);
	  //fRes = CryptAcquireContext(&hProvide,"SetCARDKeyContainer",sProvName,dwProvType, CRYPT_SILENT);
	  fRes = CryptAcquireContext(&hProvide,NULL,sProvName,dwProvType, CRYPT_VERIFYCONTEXT);
	  if(fRes) {
	    //the extra csp might give wrong answer. We should ask from provider, why.
	    //The following is the work-around -- try to lookup key container from the card.
	    //if the result is negative this is a not the csp what is needed.
	    fRes=CryptGetProvParam(hProvide, PP_ENUMCONTAINERS, pbData, &cbData,CRYPT_FIRST);	   
	  }
	}
	if (fRes == TRUE) { // && dwProvType == 2)
	  //set global values
	  LOG("CSP %s accepted",sProvName);
	  strncpy(oG_sCSPName, sProvName, sizeof(oG_sCSPName));
	  CryptReleaseContext(hProvide, 0);
	  psRes = oG_sCSPName;
	  break;
        }
      }
    }
    //hProvide = 0;
    CryptReleaseContext(hProvide, 0);
    dwIndex++;
  }
  if (hKey != NULL)
    RegCloseKey(hKey);
  return(psRes);
}


static void DigiCrypt_ReleaseFirstAllowedCSP(void)
{
  //clear global values
  if (oG_hProvider != 0)
    CryptReleaseContext(oG_hProvider, 0);
  oG_hProvider = 0;
  oG_sCSPName[0] = 0;
}

static char *DigiCrypt_GetDefaultKeyContainerName(char *psCSPName)
{
  char *psRes = NULL;
  HCRYPTPROV hProvider;
  BOOL  fRes;
  DWORD dwFlags = CRYPT_VERIFYCONTEXT;
  BYTE pbData[dNAME_ITEM_LEN+1];
  DWORD cbData = dNAME_ITEM_LEN;
  DWORD dwError;
  DWORD dwProvType;

  ZeroMemory(pbData,cbData);
  ZeroMemory(oG_sKeyContainerName,1000);
  dwProvType = DigiCrypt_FindContext_GetCSPType(psCSPName);
  //LOG("GetDefaultKeyContainerName CSP=%s",psCSPName);
  if (lstrcmp(psCSPName,psData_Extra_CSP_Name) != 0)
    fRes = CryptAcquireContext(&hProvider,NULL,psCSPName,dwProvType, CRYPT_SILENT);
  else
    fRes = CryptAcquireContext(&hProvider,NULL,psCSPName,dwProvType, CRYPT_VERIFYCONTEXT);
  if (fRes == FALSE && dwFlags == CRYPT_SILENT) {
    //by description must be CRYPT_VERIFYCONTEXT
    fRes = CryptAcquireContext(&hProvider,NULL,psCSPName,dwProvType, CRYPT_VERIFYCONTEXT);
  }
  if (fRes == TRUE) {
    cbData = dNAME_ITEM_LEN;
    fRes = CryptGetProvParam(hProvider, PP_CONTAINER, pbData, &cbData, 0);
    /*if (fRes == FALSE)
      dwError = GetLastError();*/
  }
  //Some cards should not have default key container
  //let try to find key containers on the card.
  if (fRes == FALSE)  {
    fRes=CryptGetProvParam(hProvider, PP_ENUMCONTAINERS, pbData, &cbData,CRYPT_FIRST);
    if (fRes == FALSE)
      dwError = GetLastError();
  }
  if (fRes == TRUE) {
    //oG_hProvider = hProvider;
    strncpy(oG_sKeyContainerName, (char *) pbData, sizeof(oG_sKeyContainerName));
    //psRes = oG_sKeyContainerName;
    DigiCrypt_ChangeContainerName(oG_sKeyContainerName);
  } else {
      
  }
  if (psRes != NULL)
    LOG("GetDefaultKeyContainerName CSP=%s",psCSPName);
  else
    LOG("GetDefaultKeyContainerName Not found");
  if (hProvider != 0)
    CryptReleaseContext(hProvider, 0);
  return(oG_sKeyContainerName);
}

static char *DigiCrypt_GetDefaultKeyContainerNameSimple(char *psCSPName)
{
  char *psRes = NULL;
  HCRYPTPROV hProvider=0;
  BOOL  fRes;
  DWORD dwFlags = 0;
  BYTE pbData[dNAME_ITEM_LEN+1];
  DWORD cbData = dNAME_ITEM_LEN;
  DWORD dwError;

  fRes = OpenProvider(&hProvider, psCSPName, dwFlags);
  //fRes = CryptAcquireContext(&hProvider,NULL,psCSPName,PROV_RSA_SIG, dwFlags);
  if (fRes == TRUE) {
    fRes = CryptGetProvParam(hProvider, PP_CONTAINER, pbData, &cbData, 0);
    if (fRes == FALSE)
      dwError = GetLastError();
  }
  if (fRes == TRUE) {
    strncpy(oG_sKeyContainerName, pbData, sizeof(oG_sKeyContainerName));
    psRes = oG_sKeyContainerName;
    DigiCrypt_ChangeContainerName(oG_sKeyContainerName);
  }
  if (hProvider != 0)
    CryptReleaseContext(hProvider, 0);
  return(psRes);
}


static PCCERT_CONTEXT  DigiCrypt_SelectFromAllCerts(void)
{
PCCERT_CONTEXT  pCertContext = NULL;
HCERTSTORE hStore;
hStore = DigiCrypt_OpenStore();
if (hStore != NULL)
  {
  while (TRUE)
    {
    pCertContext = CertEnumCertificatesInStore(hStore,pCertContext);
    if (pCertContext == NULL)
      break;
    else
      {
      //TEST
      //Test_ReadCertDataC(pCertContext);
      //END TEST
      RunDlg_AddItem(pCertContext,TRUE);
      }
    }
  pCertContext = RunDlg_RunDlg();
  }
return(pCertContext);
}

static void  DigiCrypt_SelectCertsFromKeyContainer(HCRYPTPROV hProv, char *psContainerName)
{
PCCERT_CONTEXT  pCertContext = NULL;
HCERTSTORE hStore;
BOOL fRelease = FALSE;
char sContainer[dNAME_ITEM_LEN+1];

if (memcmp(psContainerName,"AUT",3) == 0)
  {
  LOG("Find1 Ignore AUT cert");
  return;
  }
hStore = DigiCrypt_OpenStore();
if (hStore != NULL)
  {
  while (TRUE)
    {
    pCertContext = CertEnumCertificatesInStore(hStore,pCertContext);
    if (pCertContext == NULL)
      break;
    else
      {
      if (DigiCrypt_GetContainerFromCert(pCertContext, sContainer, dNAME_ITEM_LEN) == TRUE)
        {

        LOG("Find1 Container %s %s",sContainer,psContainerName);
		if (lstrcmp(sContainer+3,psContainerName+3) == 0)
		  {
          LOG("Find1 Container %s accepted",sContainer);
          RunDlg_AddItem(pCertContext,TRUE);
		  }
        }
      }
    }
  }
else
  LOG("Find1 Can't open store");
if (fRelease == TRUE)
  CryptReleaseContext(hProv, 0);
}

static PCCERT_CONTEXT  DigiCrypt_SelectFromAllKeysCerts(HCRYPTPROV hProvider)
{
PCCERT_CONTEXT  pCertContext = NULL;
HCRYPTPROV hProv;
BYTE pbData[dNAME_ITEM_LEN+1];
DWORD cbData = dNAME_ITEM_LEN;
DWORD dwFlag;
BOOL fRes;
BOOL fRelease = FALSE;
CRYPT_KEY_PROV_INFO* poKeyInfo = NULL;
char sContainer[dNAME_ITEM_LEN+1];

hProv = hProvider;


if (hProv == 0)
  {
  fRes = OpenProvider(&hProv, oG_sCSPName, CRYPT_VERIFYCONTEXT);
  //fRes = CryptAcquireContext(&hProv,NULL,oG_sCSPName,PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
  if (fRes == FALSE)
    {
		
    LOG("Find1 - Can't open provider");
    return(pCertContext);
	}
  fRelease = TRUE;
  }
  dwFlag = CRYPT_FIRST;
  fRes = TRUE;
  while (fRes == TRUE)
    {
    cbData = dNAME_ITEM_LEN;
    cbData = 0;
    fRes = CryptGetProvParam(hProv, PP_ENUMCONTAINERS, NULL, &cbData, dwFlag);
    if (fRes == TRUE)
      fRes = CryptGetProvParam(hProv, PP_ENUMCONTAINERS, pbData, &cbData, dwFlag);
    dwFlag = 0;

    if (fRes == FALSE)
      {
      if (GetLastError() == ERROR_NO_MORE_ITEMS)
        {
        LOG("Find1 End");
        fRes = TRUE;
        break;
        }
      }
	  else
	    {
        LOG("Find1 select certs from %s",pbData);
        DigiCrypt_SelectCertsFromKeyContainer(hProv, pbData); 
	    }
    }
  pCertContext = RunDlg_RunDlg();
  //we have selected the cert, but do we know corresponding key?
  //let change values of globals when these are different
  if(DigiCrypt_GetContainerFromCert(pCertContext, sContainer, dNAME_ITEM_LEN) == TRUE) {
    strncpy(oG_sKeyContainerName, sContainer, sizeof(oG_sKeyContainerName));
  }
  if(fRelease == TRUE)
    CryptReleaseContext(hProv, 0);
  return(pCertContext);
}


static BOOL DigiCrypt_IsValidCert(PCCERT_CONTEXT  pCertContext, BOOL fTimeCheck)
{
BOOL  fIsValid = FALSE;
BOOL  fRes = FALSE;
BOOL  fKuCheck = TRUE;
BYTE  bKeyUsageBits = CERT_NON_REPUDIATION_KEY_USAGE;
DWORD dwKeyUsageBytes = 1;
// VS use auth certs if key_usage_check = 0
fKuCheck = (BOOL)ConfigItem_lookup_int("KEY_USAGE_CHECK", 1);
bKeyUsageBits = fKuCheck ? CERT_NON_REPUDIATION_KEY_USAGE : 0;
//LOG("KEY_USAGE_CHECK: %d ku: %d", fKuCheck, bKeyUsageBits); 
//Old version
//FILETIME oCurrentTime;
if (pCertContext != NULL && pCertContext->pCertInfo != NULL)
  {
  //not needed (info from Tarmo Milva)
  //if (DigiCrypt_CertIsSig(pCertContext) == TRUE)
    fRes = CertGetIntendedKeyUsage(X509_ASN_ENCODING,pCertContext->pCertInfo,&bKeyUsageBits,dwKeyUsageBytes);
  //else
  //  fRes = FALSE;
  if (fRes == TRUE)
    {
    //LOG("KU non-repu: %d", (bKeyUsageBits & CERT_NON_REPUDIATION_KEY_USAGE));
    if(!fKuCheck || (bKeyUsageBits & CERT_NON_REPUDIATION_KEY_USAGE))
	  fIsValid = TRUE;
    if(bKeyUsageBits & CERT_KEY_CERT_SIGN_KEY_USAGE) // don't display CA certs
	  fIsValid = FALSE;
	}
  if (fIsValid == TRUE && fTimeCheck == TRUE)
    {
    //Old version
    //GetSystemTimeAsFileTime(&oCurrentTime);
	  //if (CompareFileTime(&oCurrentTime, &pCertContext->pCertInfo->NotBefore) < 0 ||
		//    CompareFileTime(&oCurrentTime, &pCertContext->pCertInfo->NotAfter) > 0 )
    //  fIsValid = FALSE;
    //New version
    //NULL, if current datetime
    if (CertVerifyTimeValidity(NULL,pCertContext->pCertInfo) != 0)
      fIsValid = FALSE;
    }
  }
return(fIsValid);
}

static void DigiCrypt_ChangeContainerName(char *psContainerName)
{
if (memcmp(psContainerName,"AUT",3) == 0)
  memmove(psContainerName,"SIG",3);
}

//dialog functions
#define DLGMAXIEMS 512
static char *psListItems[DLGMAXIEMS];
static PCCERT_CONTEXT psListItemsCert[DLGMAXIEMS];
static int iListItems=0;

static void  RunDlg_Clear(void)
{
int iI;
for (iI=0; iI < DLGMAXIEMS;++iI)
  {
  psListItems[iI] = NULL;
  psListItemsCert[iI] = NULL;
  }
iListItems=0;
}

static BOOL  RunDlg_AddItem(PCCERT_CONTEXT  pCertContext, BOOL fTimeCheck)
{
BOOL fRes = TRUE;
BOOL fAddToList = TRUE;
char *psData;
int  iI, len;
if (iListItems == (DLGMAXIEMS-1))
  return(FALSE);
if (iListItems == 0)
  {
  for (iI=0; iI < DLGMAXIEMS;++iI)
    {
    psListItems[iI] = NULL;
    psListItemsCert[iI] = NULL;
    }
  }
if (pCertContext != NULL)
  {
  fAddToList = DigiCrypt_IsValidCert(pCertContext,fTimeCheck);
  if (fAddToList == TRUE)
    {
	  len = dSTRING_ITEM_LEN*4;
    psListItems[iListItems] = (char *)LocalAlloc(LMEM_ZEROINIT,(len));
    psListItemsCert[iListItems] = CertDuplicateCertificateContext(pCertContext);
    //Make data buffer for list
    psData = psListItems[iListItems];
    RunDlg_FillItem(pCertContext, psData, len);
    ++iListItems;
	}
  }
return(fRes);
}


static PCCERT_CONTEXT  RunDlg_RunDlg(void)
{
PCCERT_CONTEXT hCert = NULL;
int iRes = -1;
int iI;
oG_fDialogUserCancel = FALSE;
if (iListItems > 1)
  {
  LOG("StartDialog");
  iRes = RunDialogUnit(psListItems, 450,300);
  if (iRes < 0)
    oG_fDialogUserCancel = TRUE;
  LOG("EndDialog");
  }
else
  {
  if (iListItems == 1)
    iRes = 0;
  }
for (iI=0; iI < iListItems;++iI)
  {
  LocalFree(psListItems[iI]);
  if (iRes != iI)
    CertFreeCertificateContext(psListItemsCert[iI]);
  else
    hCert = psListItemsCert[iI];
  }
iListItems = 0;
return(hCert);
}

static BOOL  RunDlg_FillItem(PCCERT_CONTEXT  pCertContext, char *psRes, int len)
{
  char sTemp[dSTRING_ITEM_LEN+1];
  SYSTEMTIME oT;
  PCERT_INFO pCertInfo;
  BOOL fRes = TRUE;
  *psRes = 0;

  if (pCertContext == NULL || pCertContext->pCertInfo == NULL || psRes == NULL)
    return(FALSE);
  pCertInfo = pCertContext->pCertInfo;
  CertGetNameString(pCertContext,CERT_NAME_SIMPLE_DISPLAY_TYPE,CERT_NAME_ISSUER_FLAG,NULL,sTemp,dSTRING_ITEM_LEN);
  if (lstrlen(sTemp) > 0) {
    strncat(psRes, sTemp, len - strlen(psRes));
    strncat(psRes, "   \t", len - strlen(psRes));
  }
  CertGetNameString(pCertContext,CERT_NAME_SIMPLE_DISPLAY_TYPE,0,NULL,sTemp,dSTRING_ITEM_LEN);
  //CorrectCharacters(sTemp);
  if (lstrlen(sTemp) > 0) {
    strncat(psRes, sTemp, len - strlen(psRes));
    strncat(psRes, "   \t", len - strlen(psRes));
  }
  if (FileTimeToSystemTime(&pCertInfo->NotBefore,&oT) == TRUE) {
    snprintf(sTemp, sizeof(sTemp), "%02d/%02d/%02d   \t",oT.wYear,oT.wMonth,oT.wDay);
    strncat(psRes, sTemp, len - strlen(psRes));
  }
  else
    fRes = FALSE;
  if (FileTimeToSystemTime(&pCertInfo->NotAfter,&oT) == TRUE) {
    snprintf(sTemp, sizeof(sTemp), "02d/%02d/%02d    \t",oT.wYear,oT.wMonth,oT.wDay);
    strncat(psRes,sTemp, len - strlen(psRes));
  }
  else
    fRes = FALSE;
  if (DigiCrypt_GetCSPFromCert(pCertContext, sTemp, dSTRING_ITEM_LEN) == TRUE)
    strncat(psRes,sTemp, len - strlen(psRes));
  return(fRes);
}

static char sLogLine[4096];
static char sLogFile[256];
static int  iLogCheck = -1;

static BOOL IsLogEnabled(void)
{
  BOOL  fRes = FALSE;
  DWORD dwRes;
  char  cVal;
  HANDLE hSearch;
  WIN32_FIND_DATA oF;
  
  if(iLogCheck == -1) {
    iLogCheck = 0;
    dwRes = GetModuleFileName(NULL, sLogFile, 255);
    //strcpy(sLogFile, "z:\\digicrypt.log"); dwRes=1;iLogCheck = 1;
    //MessageBox(NULL,sLogFile,"LogFile=",MB_OK|MB_SYSTEMMODAL|MB_ICONERROR);
    while (dwRes > 1) {
      cVal = sLogFile[dwRes-1];
      if (cVal == '.') {
	strncat(sLogFile, "log", sizeof(sLogFile) - strlen(sLogFile));
	hSearch = FindFirstFile(sLogFile,&oF);
	if (hSearch != INVALID_HANDLE_VALUE) {
	  iLogCheck = 1;
	  FindClose(hSearch);
        }
	break;
      }
      --dwRes;
    }
  }
  fRes = (BOOL)iLogCheck;
  return(fRes);
}

void LOG(char *psMsgFmt, ...)
{
  int iLen;
  char buff[200];
  va_list ArgList;
  va_start(ArgList, psMsgFmt);
  iLen = wvsprintf((LPTSTR)sLogLine, (LPTSTR)psMsgFmt, ArgList);
  snprintf(buff, sizeof(buff), (LPTSTR)psMsgFmt,ArgList);
  //MessageBox(NULL,(LPTSTR)sLogLine,"Teade",0);
  va_end(ArgList);
  if (IsLogEnabled() == TRUE)
    IntLogToFile(sLogLine,iLen);
}

static void IntLogToFile(char *psMsg, int iMsgLen)
{
char sLogFormat1[]="%02d%02d%02d %02d:%02d.%02d ";
char sTimeBuf[64];
HANDLE hFile;
DWORD  dwLen;
SYSTEMTIME oTime;
if (psMsg == NULL || iMsgLen == 0)
  return;
GetLocalTime(&oTime);
wsprintf((LPTSTR)sTimeBuf,(LPTSTR)sLogFormat1, oTime.wYear-2000, oTime.wMonth, oTime.wDay,
                              oTime.wHour, oTime.wMinute, oTime.wSecond);
hFile = CreateFile((LPCTSTR)sLogFile,
                   GENERIC_READ|GENERIC_WRITE,FILE_SHARE_WRITE, NULL,
                   OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

if (hFile != INVALID_HANDLE_VALUE)
  {
  if (psMsg != NULL)
    {
    SetFilePointer(hFile,0,NULL,FILE_END);
    WriteFile(hFile,sTimeBuf, strlen(sTimeBuf), &dwLen, NULL);
    if (iMsgLen < 0)
      iMsgLen = strlen(psMsg);
    if (iMsgLen > 0)
      WriteFile(hFile,psMsg, iMsgLen, &dwLen, NULL);
    WriteFile(hFile,"\r\n", 2, &dwLen, NULL);
    }
  CloseHandle(hFile);
  }
}



