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

/*!
 * \file $RCSfile: CA_CMP_Util.h,v $
 * \version $Revision: 1.87 $
 * \date $Date: 2005/09/07 16:25:13 $
 * \author $Author: dedal $
 *
 * \brief CMP Utils
 */

#ifndef __CA_CMP_UTIL_H
#define __CA_CMP_UTIL_H
#undef min
#undef max

#include "ASN1Util.h"
#include "ASN1Traits.h"
#include "EncodeAnd.h"
#include "ChainUtil.h"
#include "PKIXCMP_Base.h"
#include "CA_CMP_RevAnnContent.h"
#include "CA_CMP_Certificate.h"
#include "CA_CMP_Requests.h"
#include "CA_CMP_ErrorMsg.h"
#include "CA_CMP_CRL.h"
#include "CPCrypt.h"

// CPCSP
#ifdef _WIN32
#include <windows.h>
#include <WinCrypt.h>
#include "WinCryptEx.h"
#else
#include "CSP_WinCrypt.h"
#endif

ASN1T_Extension * ASN1T_Extensions_find_item(
    const ASN1T_Extensions& extensions, const ASN1TObjId &extnID );
const void* ASN1T_Extensions_find(
    const ASN1T_Extensions& extensions, const ASN1TObjId &extnID,
    bool &critical );

void str1cpy( char *dest, const char *src, size_t len, const char*text );
void str1cpy( wchar_t *dest, const char *src, size_t len, const char*text );
void str1cpy8( wchar_t *dest, const ASN1UTF8String &src, size_t len, const char*text, ASN1CTXT *pctxt );
void ASN1SignatureToBlob(CACMPT_BLOB& signature_blob, const ASN1TDynBitStr &signature, bool fFormat = true);

class CACMPT_ASN1BERDecodeBuffer : public ASN1BERDecodeBuffer {
public:
    CACMPT_ASN1BERDecodeBuffer (const ASN1OCTET* pMsgBuf, int msgBufLen)
	: ASN1BERDecodeBuffer (pMsgBuf, msgBufLen) {}
    CACMPT_ASN1BERDecodeBuffer (const CACMPT_BLOB &msgBuf)
	: ASN1BERDecodeBuffer (msgBuf.pbData, msgBuf.cbData) {}
    CACMPT_ASN1BERDecodeBuffer ()
	: ASN1BERDecodeBuffer () {}
    int setBuffer( const CACMPT_BLOB &src ) {
	mBufSetFlag = FALSE;
	return ASN1BERDecodeBuffer::setBuffer( (ASN1OCTET*)src.pbData, src.cbData );
    }
    int setBuffer( const BYTE *src, size_t len ) {
	mBufSetFlag = FALSE;
	return ASN1BERDecodeBuffer::setBuffer( src, static_cast<int>(len) );
    }
} ;

// множество имен Store
typedef std::set<CertificateStore> CertificateStore_set;

class CertChainContext : public CertCC
{
public:
    CertChainContext(bool a = true, bool b = true, bool c = true) : CertCC(a, b, c) {}
    ~CertChainContext() {}

    // функции добавления начальных установок
    void add_list( const CACMPT_BLOB *cert );

    void set_list( const encoded_certificate_list *lst )
    { clear_list(); add_list( lst ); }
    void set_list( const ASN1TSeqOfList &extra )
    { clear_list(); add_list( extra ); }
    void add_list( const encoded_certificate_list *lst );
    void add_list( const ASN1TSeqOfList &extra );

    void add_crl_list( const encoded_crl_list *lst );

    void clear_list();

    void add_trust_list( const CACMPT_BLOB *cert );
    void add_trust_list( const encoded_certificate_list *lst );

    void set_trust( const encoded_certificate_list *lst )
    { add_trust_list( lst ); }

    void add_stores( const CertificateStore_set *stores);
    void add_stores( const CertificateStore &store);
    void add_crl_stores( const CertificateStore &store);
    void add_crl_stores( const CertificateStore_set *stores);

    // old style
    void add_stores( const CertificateStore *stores,
    	size_t stores_quant );
    void add_crl_stores( const CertificateStore *stores,
    	size_t stores_quant );

    bool verify_crl(PCCRL_CONTEXT p);
    bool verify_message( ASN1BEREncodeBuffer &enc_buffer,
	ASN1C_PKIMessage &message,
	const ASN1TDynBitStr &signature, const DATA_BLOB &signer,
	const ASN1T_AlgorithmIdentifier &alg,
	const DATA_BLOB *sender_kit);
    // функции получения результата
    void get_chain( encoded_certificate_list &chain ) const;
};

class CACMPT_TimeChoiceImpl;
class CACMPT_TimeChoice
{
public:
    enum Type
    {
	t_utcTime = 1,
	t_generalTime = 2
    };
public:
    CACMPT_TimeChoice();
    CACMPT_TimeChoice( const CACMPT_Date& time);
    ~CACMPT_TimeChoice();

    Type get_type() const;
    const CACMPT_Date& get_time() const;
    void set_time( const CACMPT_Date& time);
private:
    CACMPT_TimeChoice( const CACMPT_TimeChoice& src);
    CACMPT_TimeChoice& operator=(const CACMPT_TimeChoice&);

    void clear();
    CACMPT_TimeChoiceImpl* pImpl_;
};

int str2dn( const wchar_t *str, ASN1T_Name &name, ASN1BEREncodeBuffer &enc_buffer );
int str2general( const wchar_t *value, ASN1T_GeneralName &name, ASN1BEREncodeBuffer &enc_buffer);

void date1cpy( CACMPT_Date &out_date, const char *in_date, int format = CACMPT_TimeChoice::t_utcTime );
inline void date1cpy( CACMPT_Date &out_date, const ASN1T_Time &in_time )
{ date1cpy( out_date, in_time.u.generalTime, in_time.t ); }

const char *date2cpy (ASN1BEREncodeBuffer &enc_buffer, const CACMPT_Date &in_date, int format);

int compare_time( const ASN1T_Time &left, const ASN1CTime &right );
inline bool operator <= ( const ASN1T_Time &left, const ASN1CTime &right )
{ return compare_time( left, right ) <= 0; }
inline bool operator >= ( const ASN1T_Time &left, const ASN1CTime &right )
{ return compare_time( left, right ) >= 0; }
inline bool operator < ( const ASN1T_Time &left, const ASN1CTime &right )
{ return compare_time( left, right ) < 0; }
inline bool operator > ( const ASN1T_Time &left, const ASN1CTime &right )
{ return compare_time( left, right ) > 0; }
inline bool operator == ( const ASN1T_Time &left, const ASN1CTime &right )
{ return compare_time( left, right ) == 0; }
inline bool operator != ( const ASN1T_Time &left, const ASN1CTime &right )
{ return compare_time( left, right ) != 0; }

int compare_time( const ASN1T_Time& left, const ASN1T_Time& right );
inline bool operator <= ( const ASN1T_Time &left, const ASN1T_Time &right )
{ return compare_time( left, right ) <= 0; }
inline bool operator >= ( const ASN1T_Time &left, const ASN1T_Time &right )
{ return compare_time( left, right ) >= 0; }
inline bool operator < ( const ASN1T_Time &left, const ASN1T_Time &right )
{ return compare_time( left, right ) < 0; }
inline bool operator > ( const ASN1T_Time &left, const ASN1T_Time &right )
{ return compare_time( left, right ) > 0; }
inline bool operator == ( const ASN1T_Time &left, const ASN1T_Time &right )
{ return compare_time( left, right ) == 0; }
inline bool operator != ( const ASN1T_Time &left, const ASN1T_Time &right )
{ return compare_time( left, right ) != 0; }

void GeneralizedNameParse(const ASN1T_GeneralName &name, CACMPT_PARSED_RDN &parsed_rdn);

typedef wchar_t CACMPT_RDN [ 8192 ];

inline void GeneralizedNameParse( const ASN1T_GeneralName &name, 
    CACMPT_PARSED_RDN &parsed_rdn, CACMPT_RDN &rdn )
{
    GeneralizedNameParse( name, parsed_rdn );
    wcscpy (rdn, parsed_rdn.tostring (CERT_X500_NAME_STR).c_str());
}

inline void GeneralizedNameParse( const ASN1T_GeneralName &name, CACMPT_RDN &rdn )
{
    CACMPT_PARSED_RDN parsed_rdn;
    GeneralizedNameParse( name, parsed_rdn, rdn );
}

ASN1GeneralizedTime
ASN1GeneralizedTime_current (ASN1BEREncodeBuffer &enc_buffer);
ASN1UTCTime
ASN1UTCTime_current (ASN1BEREncodeBuffer &enc_buffer);
ASN1UTCTime
ASN1UTCTime_min (ASN1BEREncodeBuffer &enc_buffer, ASN1UTCTime a, ASN1UTCTime b);

ASN1ConstCharPtr
ASN1Time_set (
    ASN1BEREncodeBuffer &enc_buffer, 
    const ASN1CTime &gtime );

ASN1UTCTime
ASN1UTCTime_add (ASN1BEREncodeBuffer &enc_buffer, ASN1UTCTime base, 
    const CACMPT_Period &date);

unsigned ASN1CMPMessage_Verify(ASN1T_PKIMessage &message,
			       const CertificateStore *add_store, int add_store_len,
			       encoded_certificate_list *path = NULL);

void ASN1CMPMessage_Parse( ASN1T_PKIMessage &asn1_message,
    PKIXCMP_Message &message );
void ASN1CMPMessage_Encode( const PKIXCMP_Message &message,
    ASN1T_PKIMessage &asn1_message,
    ASN1BEREncodeBuffer &enc_buffer,
    ASN1BERDecodeBuffer &dec_buffer );

CACMPT_BLOB
ASN1CMPMessage_Sign( ASN1T_PKIMessage &asn1t_message,
    ASN1BEREncodeBuffer& enc_buffer,
    HCRYPTPROV hProv, 
    DWORD dwKeySpec,
    const encoded_certificate_list &extra_certs);

CACMPT_BLOB
ASN1CMPMessage_EncodeEx(ASN1T_PKIMessage &asn1t_message,
    ASN1BEREncodeBuffer& enc_buffer,
    HCRYPTPROV hProv,
    DWORD dwKeySpec,
    const encoded_certificate_list &extra_certs
);

ASN1T_Name&
ASN1T_Name_set (
    CACMPT_ASN1BERDecodeBuffer& dec_buffer,
    const CACMPT_PARSED_RDN& RDN);

void ASN1T_Attributes_add (ASN1CTXT* pctxt, ASN1TSeqOfList& attributes, ASN1OBJID& oid, void *decoded);

void ASN1T_Extensions_add_basicConstraints(ASN1CTXT* pctxt, ASN1T_Extensions& extensions);

void
ASN1T_Extensions_add_subjectKeyIdentifier (
	HCRYPTPROV hProv, 
	ASN1CTXT* pctxt,
	ASN1T_Extensions& extensions, 
	ASN1TDynBitStr& subjectPublicKey,
	bool fReplace = false);

void 
ASN1T_Extensions_add_aKI_and_iAN (
	ASN1CTXT* pctxt,
	ASN1T_Extensions& extensions, 
	const ASN1T_Certificate& asn1t_ca);

void
ASN1T_Extensions_add_AIA (
	ASN1CTXT* pctxt,
	ASN1T_Extensions& extensions, 
	const ASN1T_Certificate& asn1t_ca);

void
ASN1T_Extensions_replace (
	ASN1CTXT* pctxt,
	ASN1T_Extensions& extensions, 
	const CACMPT_Extension& obj);

void
ASN1T_Extensions_set (
	ASN1CTXT* pdecctxt,
	ASN1T_Extensions& asn1t_extensions, 
	const CACMPT_Extensions &Extensions);

void
ASN1T_Extensions_get (
    const ASN1T_Extensions& asn1t_extensions, 
    CACMPT_Extensions &Extensions);

/* dim: made static */
void SubjectPublicKeyInfo_Parse(CACMPT_PublicKeyInfo &dest, const ASN1T_AlgorithmIdentifier &src);

void tbsCertificateParse(ASN1T_TBSCertificate &cert, CertificateInfo *dest);

void Certificate_Parse(ASN1T_Certificate *cert, const CACMPT_BLOB &c_msg, CertificateInfo *dest);

void
ASN1T_BigInt_gen (HCRYPTPROV hProv, ASN1OCTET* buf, int len);

void
CACMP_GenContainerName (HCRYPTPROV hProv, char szContainer[256]);

class CertificateTemplate
{
public:
    CertificateTemplate();
    ~CertificateTemplate();

    ASN1BEREncodeBuffer enc_buffer;
    CACMPT_ASN1BERDecodeBuffer dec_buffer;
    ASN1T_PKIMessage asn1t_request; //?
    ASN1T_Certificate asn1t_cert;
    ASN1T_Certificate asn1t_ca;
};

// missing id-it-xxx OID's in asn1data
// These OID's are used in GenM/GenRep

#define id_it_ResumeCertificate id_CryptoPro_it_ResumeCertificate
#define id_it_GetMessage id_CryptoPro_it_GetMessage
#define id_it_GetMessages id_CryptoPro_it_GetMessages
#define id_it_ChangeNameReq id_CryptoPro_it_ChangeNameReq
#define id_it_ResumeCertificateReply id_CryptoPro_it_ResumeCertificateReply

ASN1T_Name* get_server_name( const CACMPT_BLOB &cert,
    ASN1BERDecodeBuffer &dec_buffer );

void add_extra_certs( ASN1BERDecodeBuffer &dec_buffer,
    ASN1T_PKIMessage &asn1t_message, 
    const encoded_certificate_list &extra_certs );

void copy_str_array( ASN1T_PKIFreeText &dest, const std::wstring *src, 
    size_t len, ASN1CTXT* pctxt );

void CertReq_Parse(ASN1T_CertificationRequest *req, RequestInfo *dest);
void CertReq_Parse(ASN1T_CertReqMessages *req, RequestInfo *dest);
void CertReq_Parse(ASN1T_RevReqContent& req, RequestInfo *dest);
void CertReq_Parse(ASN1T_RevDetails& asn1t_rev_details, RequestInfo *dest);

void FreeText_Encode( ASN1CTXT *pctxt, ASN1T_PKIFreeText &dest,
    const FreeText &src );

void FreeText_Parse( ASN1CTXT *pctxt, FreeText &dest,
    const ASN1T_PKIFreeText &src );

DWORD get_pin_load(WndProv &wnd_prov, HCRYPTPROV hProv, const char *name, short n, int num);

CACMPT_BLOB GetPinInfo( HCRYPTPROV hProv );

void get_reader_list( HCRYPTPROV hProv, ReaderList& );

bool create_with_change( WndProv &wnd_prov, 
    const char *provider, DWORD dwProvType, 
    const char *reader, const char *container, 
    short i, short n, HCRYPTPROV *hProv,
    DWORD *hProvInt );
void split_container_name( const char *name, 
    std::string &reader_name, std::string &container_name );
std::string get_container( HCRYPTPROV hProv );
std::string get_provider( HCRYPTPROV hProv );
std::string get_unique( HCRYPTPROV hProv );

class RetrySetProvParam : public Retry
{
public:
    RetrySetProvParam( HCRYPTPROV hProv, DWORD dwParam, const BYTE *pbData,
	DWORD dwFlags ) : m_hProv( hProv ), m_dwParam( dwParam ), 
	m_pbData( pbData ), m_dwFlags( dwFlags ) {}
protected:
    virtual BOOL call( void ) 
    { return CryptSetProvParam( m_hProv, m_dwParam, (BYTE*)m_pbData, m_dwFlags ); }
    HCRYPTPROV m_hProv;
    DWORD m_dwParam;
    const BYTE *m_pbData;
    DWORD m_dwFlags;
};

class RetryGetProvParam : public Retry
{
public:
    RetryGetProvParam( HCRYPTPROV hProv, DWORD dwParam, BYTE *pbData,
	DWORD *pdwDataLen, DWORD dwFlags ) : m_hProv( hProv ), 
	m_dwParam( dwParam ), m_pdwDataLen( pdwDataLen ), m_pbData( pbData ), 
	m_dwFlags( dwFlags ) {}
protected:
    virtual BOOL call( void ) 
    { 
	DWORD dwDataLen = *m_pdwDataLen;
	if( CryptGetProvParam( m_hProv, m_dwParam, m_pbData, &dwDataLen,
	    m_dwFlags ) )
	{
	    *m_pdwDataLen = dwDataLen;
	    return TRUE;
	}
	return FALSE;
    }
    HCRYPTPROV m_hProv;
    DWORD m_dwParam;
    DWORD *m_pdwDataLen;
    BYTE *m_pbData;
    DWORD m_dwFlags;
};

class RetryAcquireContext : public Retry
{
public:
    RetryAcquireContext( HCRYPTPROV *hProv, const char *szContainer, 
	const char *szProvider, DWORD dwProvType, DWORD dwFlags,
	HCRYPTPROV hProvVerify );
    virtual BOOL call( void );
protected:
    HCRYPTPROV *m_hProv;
    std::string m_szContainer;
    const char *m_szProvider;
    DWORD m_dwProvType;
    DWORD m_dwFlags; 
    ReaderList list;
};

ASN1ConstCharPtr DateToASN1GeneralizedTime( ASN1CTXT* pctxt, const CACMPT_Date& date);

// only for t == T_GeneralName_directoryName
void ASN1T_GeneralName_set(
    ASN1CTXT* pctxt,
    ASN1T_GeneralName& dest,
    const CACMPT_BLOB& src); 

// only for t == T_GeneralName_directoryName
void ASN1T_GeneralName_get(
    const ASN1T_GeneralName& src,
    CACMPT_BLOB& dest); 

ASN1ConstCharPtr DWORDToASN1BigInteger( ASN1CTXT* pctxt, DWORD val);
DWORD ASN1BigIntegerToDWORD( ASN1ConstCharPtr val);

void ASN1T_SignerInfo_get( CACMPT_SignerInfo& dest, const ASN1T_SignerInfo& src);

std::string get_sub_xml( std::string &src );
std::string get_not_xml( std::string &src );
std::string get_sub_xml_lend( std::string &src );

class ASN1GeneralizedTime_traits
{
public:
    typedef ASN1C_InvalidityDate ASN1_C;

    static void set(
	ASN1CTXT* pctxt,
	ASN1GeneralizedTime& dest,
	const CACMPT_Date& src);
    static void get(
	const ASN1GeneralizedTime& src,
	CACMPT_Date& dest);
    static void copy(
	ASN1CTXT* pctxt,
	const ASN1GeneralizedTime& src,
	ASN1GeneralizedTime& dest);
};

class ASN1T_Extension_traits
{
public:
    typedef ASN1C_Extension ASN1_C;

    static void set(
	ASN1CTXT* pctxt,
	ASN1T_Extension& dest,
	const CACMPT_Extension& src);
    static void get(
	const ASN1T_Extension& src,
	CACMPT_Extension& dest);
    static void copy(
	ASN1CTXT* pctxt,
	const ASN1T_Extension& src,
	ASN1T_Extension& dest);
};

class ASN1T_PKIStatusInfo_traits
{
public:
    typedef ASN1C_PKIStatusInfo ASN1_C;

    static void set(
	ASN1CTXT* pctxt,
	ASN1T_PKIStatusInfo& dest,
	const ErrorMsgInfo& src);
    static void get(
	const ASN1T_PKIStatusInfo& src,
	ErrorMsgInfo& dest);
    static void copy(
	ASN1CTXT* pctxt,
	const ASN1T_PKIStatusInfo& src,
	ASN1T_PKIStatusInfo& dest);
};

class ASN1T_SignerInfo_traits
{
public:
    typedef ASN1C_SignerInfo ASN1_C;

    static void set(
	ASN1CTXT* pctxt,
	ASN1T_SignerInfo& dest,
	const CACMPT_SignerInfo& src);
    static void get(
	const ASN1T_SignerInfo& src,
	CACMPT_SignerInfo& dest);
    static void copy(
	ASN1CTXT* pctxt,
	const ASN1T_SignerInfo& src,
	ASN1T_SignerInfo& dest);
};

class ASN1T_SignerInfos_traits
    : public ASN1TSeqOfList_traits<
	ASN1T_SignerInfo,
	ASN1T_SignerInfo_traits,
	CACMPT_SignerInfo,
	CACMPT_SignerInfos>
{
public:
    typedef ASN1C_SignerInfos ASN1_C;
};

class ASN1T_RevAnnContent_traits
{
public:
    typedef ASN1C_RevAnnContent ASN1_C;

    static void set(
	ASN1CTXT* pctxt,
	ASN1T_RevAnnContent& dest,
	const CACMPT_RevAnnContent& src);
    static void get(
	const ASN1T_RevAnnContent& src,
	CACMPT_RevAnnContent& dest);
    static void copy(
	ASN1CTXT* pctxt,
	const ASN1T_RevAnnContent& src,
	ASN1T_RevAnnContent& dest);
};

class ASN1T_Extensions_traits
    : public ASN1TSeqOfList_traits<
	ASN1T_Extension,
	ASN1T_Extension_traits,
	CACMPT_Extension,
	CACMPT_Extensions>
{
public:
    typedef ASN1C_Extensions ASN1_C;
};

// используется в Службах::AuditLogEncode.cpp
class ASN1UTF8String_traits
{
public:
    static void set(
	ASN1CTXT* pctxt,
	ASN1UTF8String& dest,
	const std::wstring& src);
    static void get(
	const ASN1UTF8String& src,
	std::wstring& dest);
};

// используется в Службах
#define sz_id_signingTime "1.2.840.113549.1.9.5"
class CACMPT_AttrSigningTime: public CACMPT_AttrValue
{
public:
    CACMPT_AttrSigningTime( const CACMPT_Date& time)
	: CACMPT_AttrValue(sz_id_signingTime,CACMPT_BLOB()),
	  time_(time)
    { encode(); }
    CACMPT_AttrSigningTime( const CACMPT_BLOB& der)
	: CACMPT_AttrValue(sz_id_signingTime,der)
    { decode(); }

    void encode();
    void decode();

    CACMPT_Date get_time() const { return time_.get_time(); }
    void set_time( const CACMPT_Date& time) { time_.set_time(time); encode(); }
private:
    CACMPT_TimeChoice time_;
};

// используются в Службах::PKIXOCSP_Request.cpp
typedef std::list<CACMPT_DistributionPoint> CACMPT_CRLDistPointsSyntax;

class ASN1IA5String_traits
{
public:
    static void set( 
	ASN1CTXT* pctxt,
	ASN1IA5String& dest, 
	const std::string& src);
    static void get(
	const ASN1IA5String& src, 
	std::string& dest);
    static void copy(
	ASN1CTXT* pctxt,
	const ASN1IA5String& src,
	ASN1IA5String& dest);
};

class ASN1T_GeneralName_traits
{
public:
    static void set(
	ASN1CTXT* pctxt,
	ASN1T_GeneralName& dest,
	const CACMPT_GeneralName& src);
    static void get(
	const ASN1T_GeneralName& src,
	CACMPT_GeneralName& dest);
    static void copy(
    	ASN1CTXT* pctxt,
    	const ASN1T_GeneralName& src,
    	ASN1T_GeneralName& dest);
};

class ASN1T_GeneralNames_traits
    : public ASN1TSeqOfList_traits<
	ASN1T_GeneralName,
	ASN1T_GeneralName_traits,
	CACMPT_GeneralName,
	CACMPT_GeneralNames>
{
public:
    typedef ASN1C_GeneralNames ASN1_C;
};

class ASN1T_ReasonFlags_traits
{
public:
    typedef ASN1C_ReasonFlags ASN1_C;

    static void set(
    	ASN1CTXT* pctxt,
    	ASN1T_ReasonFlags& dest,
    	const CACMPT_ReasonFlags& src);
    static void get(
    	const ASN1T_ReasonFlags& src,
    	CACMPT_ReasonFlags& dest);
};

class ASN1T_DistributionPointName_traits
{
public:
    typedef ASN1C_DistributionPointName ASN1_C;

    static void set(
    	ASN1CTXT* pctxt,
    	ASN1T_DistributionPointName& dest,
    	const CACMPT_DistributionPointName& src);
    static void get(
    	const ASN1T_DistributionPointName& src,
    	CACMPT_DistributionPointName& dest);
};

class ASN1T_DistributionPoint_traits
{
public:
    typedef ASN1C_DistributionPoint ASN1_C;

    static void set(
    	ASN1CTXT* pctxt,
    	ASN1T_DistributionPoint& dest,
    	const CACMPT_DistributionPoint& src);
    static void get(
    	const ASN1T_DistributionPoint& src,
    	CACMPT_DistributionPoint& dest);
    static void copy(
    	ASN1CTXT* pctxt,
    	const ASN1T_DistributionPoint& src,
    	ASN1T_DistributionPoint& dest);
};

class ASN1T_CRLDistPointsSyntax_traits
{
public:
    typedef ASN1C_CRLDistPointsSyntax ASN1_C;

    static void set(
	ASN1CTXT* pctxt,
	ASN1T_CRLDistPointsSyntax& dest,
	const CACMPT_CRLDistPointsSyntax& src);
    static void get(
	const ASN1T_CRLDistPointsSyntax& src,
	CACMPT_CRLDistPointsSyntax& dest);
    static void copy(
	ASN1CTXT* pctxt,
	const ASN1T_CRLDistPointsSyntax& src,
	ASN1T_CRLDistPointsSyntax& dest);
};

struct CACMPT_AccessDescription
{
    CACMPT_OID accessMethod;
    CACMPT_GeneralName accessLocation;
};
typedef std::list<CACMPT_AccessDescription> CACMPT_AuthorityInfoAccessSyntax;

class ASN1T_AccessDescription_traits
{
public:
    typedef ASN1C_AccessDescription ASN1_C;

    static void set(
	ASN1CTXT* pctxt,
	ASN1T_AccessDescription& dest,
	const CACMPT_AccessDescription& src);
    static void get(
	const ASN1T_AccessDescription& src,
	CACMPT_AccessDescription& dest);
    static void copy(
	ASN1CTXT* pctxt,
	const ASN1T_AccessDescription& src,
	ASN1T_AccessDescription& dest);
};

class ASN1T_AuthorityInfoAccessSyntax_traits
{
public:
    typedef ASN1C_AuthorityInfoAccessSyntax ASN1_C;

    static void set(
	ASN1CTXT* pctxt,
	ASN1T_AuthorityInfoAccessSyntax& dest,
	const CACMPT_AuthorityInfoAccessSyntax& src);
    static void get(
	const ASN1T_AuthorityInfoAccessSyntax& src,
	CACMPT_AuthorityInfoAccessSyntax& dest);
};

class ASN1T_Certificate_traits
{
public:
    typedef ASN1C_Certificate ASN1_C;

    // обе используются в Службах
    static void set(
    	ASN1CTXT* pctxt,
    	ASN1T_Certificate& dest,
    	const CACMPT_BLOB& src);
    static void get(
    	const ASN1T_Certificate& src,
    	CACMPT_BLOB& dest);
    // используется в CMSSignedMessage.cpp
    static void copy(
    	ASN1CTXT* pctxt,
    	const ASN1T_Certificate& src,
    	ASN1T_Certificate& dest);
};

class prov_handle
{
public:
    prov_handle() : handle_(0) {}
    ~prov_handle() { release(); }
    HCRYPTPROV get() { return handle_; }
    bool acquire( LPCTSTR pszContainer, LPCTSTR pszProvider, DWORD dwProvType, DWORD dwFlags)
    {
	if(handle_) release();
	return ::CryptAcquireContext(
	    &handle_,pszContainer,pszProvider,dwProvType,dwFlags) == TRUE;
    }
    bool acquire_any();
    bool acquire_default( ALG_ID AlgId);
    bool acquire_default( const CACMPT_BLOB& certificate);
    void release() {
	if(handle_) {
	    ::CryptReleaseContext(handle_,0);
	    handle_ = 0;
	}
    }
private:
    HCRYPTPROV handle_;
};

class hash_handle
{
public:
    hash_handle() : handle_(0) {}
    ~hash_handle() { destroy(); }
    HCRYPTHASH get() const { return handle_; }
    void set( HCRYPTHASH hHash ) { handle_ = hHash; }
    HCRYPTHASH release() { HCRYPTHASH h = handle_; handle_ = 0; return h; }
    bool create( HCRYPTPROV hProv, ALG_ID Algid, HCRYPTKEY hKey, DWORD dwFlags)
    {
	if(handle_) destroy();
	return ::CryptCreateHash(hProv,Algid,hKey,dwFlags,&handle_) == TRUE;
    }
    void destroy() {
	if(handle_) {
	    ::CryptDestroyHash(handle_);
	    handle_ = 0;
	}
    }
private:
    HCRYPTHASH handle_;
};

ASN1T_SubjectPublicKeyInfo&
ASN1T_SubjectPublicKeyInfo_set (
    HCRYPTPROV hProv,
    DWORD dwKeySpec,
    ASN1CTXT* pdecctxt
    );

// используется в Службах::pkixtsp/
std::vector<CERT_BLOB> CACMPTToCRYPTCerts(
    const encoded_certificate_list* certificates,
    std::vector<CACMPT_BLOB>& data);

class ASN1T_Time_traits
{
public:
    typedef ASN1C_Time ASN1_C;

    static void set(
	ASN1CTXT* pctxt,
	ASN1T_Time& dest,
	const CACMPT_TimeChoice& src);

    static void get(
	const ASN1T_Time& src,
	CACMPT_TimeChoice& dest);
};

class Asn1EncodeException : public Asn1Exception
{
public:
    explicit Asn1EncodeException( const char *msg = "Asn1 encode fail.", const char *f = NULL, int l = 0 )
	: Asn1Exception( msg, f, l ) {}
};

ASN1TDynBitStr* ASN1EncodeBuffer_EncodeAndSignUnsafe (
    HCRYPTPROV hProv,
    DWORD dwKeySpec,
    ASN1BEREncodeBuffer &enc_buffer,
    ASN1CType& obj
);

template <class T>
ASN1TDynBitStr* ASN1EncodeBuffer_EncodeAndSign (
    HCRYPTPROV hProv,
    DWORD dwKeySpec,
    ASN1BEREncodeBuffer &enc_buffer,
    T& obj) {

    // compensating missing context reference count decrement for objCopy.msgData
    Asn1CtxtUnrefInDestructor<T> objCopy(obj);
    return ASN1EncodeBuffer_EncodeAndSignUnsafe(hProv,dwKeySpec,enc_buffer,objCopy);
}

#endif // __CA_CMP_UTIL_H
