#ifndef _ISPRIVATEKEYVALIDONTIME_H_INCLUDED
#define _ISPRIVATEKEYVALIDONTIME_H_INCLUDED

#if defined(_PKIVALIDATOR_STDAFX_H_INCLUDED) || defined(CPP_PRIVATE_KEY_USAGE_VALIDATOR_OBJECT_H_) || defined(REPROV_UNIX)
#include "asn1/Extension.h"
#endif 
#ifndef UNIX
#include <windows.h>
#else
#include <CSP_WinDef.h>
#endif
#include "WinCryptEx.h"
#ifdef UNIX
#ifndef DATE
#define DATE CryptoPro::CDateTime
#endif
#endif

static inline bool IsPrivateKeyValidOnTime(
    const FILETIME& time,
    bool hasPkupExtension,
    const FILETIME& certNotBefore,
    const FILETIME& certNotAfter,
    const FILETIME *pPkupNotBefore,
    const FILETIME *pPkupNotAfter)
{
    const FILETIME *pNotBefore = 0;
    const FILETIME *pNotAfter = 0;

    if(!hasPkupExtension) {
	pNotBefore = &certNotBefore;
	pNotAfter = &certNotAfter;
    } else {
	pNotBefore = pPkupNotBefore;
	pNotAfter = pPkupNotAfter;
    }

    return ( ( !pNotBefore || ( CompareFileTime(&time,pNotBefore) >= 0 ) )
	&& ( !pNotAfter || ( CompareFileTime(&time,pNotAfter) <= 0 ) ) );
}

#if defined(_PKIVALIDATOR_STDAFX_H_INCLUDED) || defined(CPP_PRIVATE_KEY_USAGE_VALIDATOR_OBJECT_H_) || defined(REPROV_UNIX)
#ifdef UNIX
#define getenv_str getenv
#include "dprint.h"
#undef CPTraceGeneral
#define CPTraceGeneral 1
#undef CPTRACE2
#undef CPTRACE
extern TSupportDbContext* pkivalidator_db_ctx;
#define CPTRACE2(ATLCategory,level,param,...)  DbTrace(DB_LOG,(FTEXT(pkivalidator_db_ctx, param),##__VA_ARGS__))
#include <cplib/DateTime.h>
#endif //UNIX

inline HRESULT IsCertContextValidOnTime(
    PCCERT_CONTEXT pCertContext,
    const FILETIME &ft,
    bool* pResult)
{
    // Нулевой pCertContext не придёт сюда даже при передаче
    // неинициализированного объекта CAPICOM.Certificate, поэтому ничего
    // дополнительно не проверяем.
    *pResult = false;

    PCERT_EXTENSION certext = ::CertFindExtension(szOID_PRIVATEKEY_USAGE_PERIOD,
        pCertContext->pCertInfo->cExtension,
        pCertContext->pCertInfo->rgExtension);

    FILETIME *pPkupNotBefore = 0;
    FILETIME *pPkupNotAfter = 0;
    std::vector<BYTE> pb;
    if (certext != 0) {
	DWORD L;
	BOOL bOK;
	bOK = ::CryptDecodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
				  szCPGUID_PRIVATEKEY_USAGE_PERIOD_Encode,
				  certext->Value.pbData, certext->Value.cbData,
				  0, NULL, &L);
	if(bOK == FALSE) {
	    CPTRACE2(CPTraceGeneral, 1, "Extension PRIVATEKEY_USAGE_PERIOD "
		     "could not be decoded: hr = 0x%08x.\n", CRYPT_E_ASN1_ERROR);
            return E_FAIL; // ?? CRYPT_E_ASN1_ERROR
	}
	pb.resize(L);

	bOK = ::CryptDecodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
				  szCPGUID_PRIVATEKEY_USAGE_PERIOD_Encode,
				  certext->Value.pbData, certext->Value.cbData,
				  0, &pb[0], &L);
	if(bOK == FALSE) {
	    CPTRACE2(CPTraceGeneral, 1, "Extension PRIVATEKEY_USAGE_PERIOD "
		     "could not be decoded: hr = 0x%08x.\n", CRYPT_E_ASN1_ERROR);
            return E_FAIL; // ?? CRYPT_E_ASN1_ERROR
	}

	PCPCERT_PRIVATEKEY_USAGE_PERIOD px = (PCPCERT_PRIVATEKEY_USAGE_PERIOD) &pb[0];
	pPkupNotBefore = px->pNotBefore;
	pPkupNotAfter = px->pNotAfter;
    }

#ifdef UNIX
#ifndef COleDateTime
#define COleDateTime CryptoPro::CDateTime
#endif
#endif

    if (IsPrivateKeyValidOnTime(ft, certext != 0,
        pCertContext->pCertInfo->NotBefore,
        pCertContext->pCertInfo->NotAfter,
        pPkupNotBefore, pPkupNotAfter)) {
        *pResult = true;
    }
    else {
	const tm bt = CryptoPro::FileTimeToTm(ft);
	char buf[256];
	if(!::strftime(buf, sizeof(buf), "%d.%m.%Y %H:%M:%S", &bt))
	    AtlThrowLastWin32();
        CPTRACE2(CPTraceGeneral, 1,
            "Certificate has not been valid on time (%s)...\n",
            buf);
    }

    return S_OK;
}

#endif // defined(_PKIVALIDATOR_STDAFX_H_INCLUDED) || defined(CPP_PRIVATE_KEY_USAGE_VALIDATOR_OBJECT_H_)

#endif /* _ISPRIVATEKEYVALIDONTIME_H_INCLUDED */
