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

/*!
 * \file $RCSfile: CA_CMP_Types.h,v $
 * \version $Revision: 1.59 $
 * \date $Date: 2005/01/24 12:36:43 $
 * \author $Author: cav $
 *
 * \brief CMP Types
 */


#ifndef CA_CMP_TYPES_H
#define CA_CMP_TYPES_H
// @devnote Platform SDK August 2001 + stlport 4.0 incompatibility fix
#ifdef _WIN32
#include <windows.h>
#include "WinCryptEx.h"
#else
#include "CSP_WinCrypt.h"
#endif

#include <string>
#include <list>

#include "ASN1Blob.h"
#include "ASN1Types.h"


class CACMPT_GeneralNameImpl;
class CACMPT_GeneralName
{
public:
    enum Type
    {
//	t_otherName = 1,
	t_rfc822Name = 2,
	t_dNSName = 3,
//	t_x400Address = 4,
	t_directoryName = 5,
//	t_ediPartyName = 6,
	t_uniformResourceIdentifier = 7,
	t_iPAddress = 8,
	t_registeredID = 9
    };
public:
    CACMPT_GeneralName();
    ~CACMPT_GeneralName();

    CACMPT_GeneralName( const CACMPT_GeneralName& src);
    CACMPT_GeneralName& operator=( const CACMPT_GeneralName& src);

    // get
    Type get_type() const;
    const std::string* get_rfc822Name() const;
    const std::string* get_dNSName() const;
    const CACMPT_BLOB* get_directoryName() const;
    const std::string* get_uniformResourceIdentifier() const;
    const CACMPT_BLOB* get_iPAddress() const;
    const CACMPT_OID* get_registeredID() const;
    // set
    void set_rfc822Name( const std::string& rfc822Name);
    void set_dNSName( const std::string& dNSName);
    void set_directoryName( const CACMPT_BLOB& directoryName);
    void set_uniformResourceIdentifier( 
	const std::string& uniformResourceIdentifier);
    void set_iPAddress( const CACMPT_BLOB& iPAddress);
    void set_registeredID( const CACMPT_OID& registeredID);
private:
    void clear();
    CACMPT_GeneralNameImpl* pImpl_;
};

typedef std::list<CACMPT_GeneralName> CACMPT_GeneralNames;

struct CACMPT_PARSED_RDN_OLD
{
    CACMPT_PARSED_RDN_OLD() {};
    CACMPT_PARSED_RDN_OLD &operator=( const CACMPT_PARSED_RDN_OLD &src )
    {
	assign( src );
	return *this;
    }
    CACMPT_PARSED_RDN_OLD( const CACMPT_PARSED_RDN_OLD& r );
    void clear()
    {
	CACMPT_PARSED_RDN_OLD tmp;
	swap( tmp );
    }
    void assign( const CACMPT_PARSED_RDN_OLD &src )
    {
	CACMPT_PARSED_RDN_OLD tmp( src );
	swap( tmp );
    }
    void swap( CACMPT_PARSED_RDN_OLD& r );

    // wide = teletexString, printableString, universalString, utf8String, bmpString
    std::string EMail; // EmailAddress pkcs-9 1 IA5String
    std::string Country; // X520countryName id-at 6 PrintableString
    std::wstring State; // X520StateOrProvinceName id-at 8  wide
    std::wstring Locality; // X520LocalityName id-at 7 wide
    std::wstring StreetAddress; // ??? id-at 9 ???
//    std::string UnstructuredAddress; // ??? RSA: 1.2.840.113549.1.9.8 ???
    std::wstring Organization; // X520OrganizationName id-at 10 wide
    std::wstring OrgUnit; // X520OrganizationalUnitName id-at 11 wide
    std::wstring Title; // X520Title id-at 12 wide
    // std::string DomainComponent; // DomainComponent 0.9.2342.19200300.100.1.25 IA5String
    // std::string DeviceSerialNumber; // X520SerialNumber id-at 5 PrintableString
    // temporary
    std::wstring GivenName; // X520name id-at 42 wide
    std::wstring Initials; // X520name id-at 41 wide
    std::wstring SurName; // X520name id-at 4 wide
    std::wstring Pseudonym; // X520Pseudonym id-at 65 wide
    std::wstring CommonName; // X520CommonName id-at 3 wide
    std::string OGRN; // OGRN
    std::string OGRNIP; // OGRNIP
    std::string INN; // INN
    std::string INNLE; // INNLE
    std::string SNILS; // SNILS
    std::wstring UnstructuredName; // UnstructuredName
    std::wstring PostalCode;
};

class CACMPT_PARSED_RDN
{
  protected:
    CACMPT_BLOB der;

    static const BYTE m_empty_der [];
    static const DWORD m_empty_der_len;
  public:
    CACMPT_PARSED_RDN () : der (m_empty_der, m_empty_der_len) { }
    CACMPT_PARSED_RDN (const CACMPT_BLOB &src) : der (src) {}
    CACMPT_PARSED_RDN (const struct asn1data::ASN1T_Name &src) { assign (src); }
    CACMPT_PARSED_RDN (const CACMPT_PARSED_RDN_OLD &src) { assign (src); }
    CACMPT_PARSED_RDN (const std::wstring& src) { assign (src); }

    CACMPT_PARSED_RDN &operator=( const CACMPT_PARSED_RDN &src );

    inline void clear () { der.assign (m_empty_der, m_empty_der_len); }
    void assign (const CACMPT_BLOB &src) { der = src; }
    void assign (const struct asn1data::ASN1T_Name &src);
    void assign (const CACMPT_PARSED_RDN_OLD &src);
    void assign (const std::wstring &src);

    std::wstring tostring (DWORD dwStrType = CERT_X500_NAME_STR|CERT_NAME_STR_NO_QUOTING_FLAG ) const;
    void parse (CACMPT_PARSED_RDN_OLD& old) const;
    void parse (class CACMPT_ASN1BERDecodeBuffer& dec_buffer, asn1data::ASN1T_Name& name) const;
};

typedef std::list<CACMPT_BLOB> blob_list;
typedef blob_list encoded_certificate_list;
typedef blob_list encoded_crl_list;

#include "ASN1Types.h"
#include "Date.h"

/**************************************************************/
/*                                                            */
/*  Internal structure                                        */
/*                                                            */
/**************************************************************/

class CACMPT_ExtValue
{    
  protected:
    std::string m_oid;
    std::string m_xer;
    CACMPT_BLOB m_der;
    void Encode (class ASN1MessageBufferIF& msgBuf, struct _ASN1OBJID&oid, void *encoded, bool encodeDER = true);
    void Decode (struct _ASN1OBJID&oid, const std::string& xer);
  public:
    CACMPT_ExtValue () {}
    ~CACMPT_ExtValue () {}

    CACMPT_ExtValue (struct _ASN1OBJID&oid, const unsigned char * pbDER, unsigned cbDER, void *decoded = NULL);
    CACMPT_ExtValue (struct _ASN1OBJID&oid, void *decoded);
    CACMPT_ExtValue (const std::string& oid, const std::string& xer);
    CACMPT_ExtValue (const CACMPT_ExtValue& ev) 
	: m_oid (ev.m_oid), m_xer (ev.m_xer), m_der (ev.m_der) {}
    CACMPT_ExtValue& operator=( const CACMPT_ExtValue& ev)
    { m_oid = ev.m_oid; m_xer = ev.m_xer; m_der = ev.m_der; return *this; }
    inline const std::string& get_oid () const { return m_oid; }
    inline const std::string& get_xer () const { return m_xer; }
    inline const CACMPT_BLOB& get_der () const { return m_der; }

 private:
    CACMPT_ExtValue (struct _ASN1OBJID&oid, const std::string& xer);
    CACMPT_ExtValue (const std::string& oid, const std::string& xer, const CACMPT_BLOB& der);
};

class CACMPT_ExtCDP: public CACMPT_ExtValue
{
  public:
    typedef std::vector<std::string> CDPList;  
    CACMPT_ExtCDP (const std::string& cdp);
    CACMPT_ExtCDP (const CDPList & CDPs);
};

class CACMPT_ExtAIA: public CACMPT_ExtValue
{
  public:
    typedef std::vector<std::string> AIAList;
    CACMPT_ExtAIA(const std::string & aia);
    CACMPT_ExtAIA(const AIAList & AIAs);
  protected:
    static std::string AIAXer(const std::string & aia);
};

class CACMPT_ExtCertificateIssuer: public CACMPT_ExtValue
{
public:
    CACMPT_ExtCertificateIssuer( const CACMPT_BLOB& der);
    ~CACMPT_ExtCertificateIssuer() {}

    const CACMPT_GeneralNames& get_issuer() const {return issuer_;}
private:
    CACMPT_ExtCertificateIssuer();
    CACMPT_GeneralNames issuer_;
};

class CACMPT_Extension
{
  protected:
    CACMPT_ExtValue m_value;
    bool            m_critical;
  public:
    CACMPT_Extension (const std::string& oid, const std::string& value, bool critical = false)
	: m_value (CACMPT_ExtValue (oid, value)), m_critical (critical) { }
    CACMPT_Extension (const CACMPT_ExtValue& value, bool critical = false)
	: m_value (value), m_critical (critical) {}
    CACMPT_Extension ()
	: m_value (CACMPT_ExtValue()), m_critical (false) {}
    CACMPT_Extension (const CACMPT_Extension& ext)
	: m_value (ext.m_value), m_critical (ext.m_critical) {}
    CACMPT_Extension& operator=( const CACMPT_Extension& ext)
    { m_value = ext.m_value; m_critical = ext.m_critical; return *this; }
    inline const std::string& get_oid () const { return m_value.get_oid(); }
    inline const std::string& get_value () const { return m_value.get_xer(); }
    inline const CACMPT_BLOB& get_der () const { return m_value.get_der(); }
    inline bool	get_critical () const { return m_critical; }

 private:
    CACMPT_Extension (const char *oid, const char *value, const CACMPT_BLOB& der, bool critical = false);
    CACMPT_Extension (const std::string& oid, const std::string& value, const CACMPT_BLOB& der, bool critical = false);
};

class CACMPT_Extensions : public std::list<CACMPT_Extension>
{
public:
    typedef std::list<CACMPT_Extension> ExtList;
    CACMPT_Extensions() : ExtList() {}
    CACMPT_Extensions( const_iterator f, const_iterator l ) : 
	ExtList(f,l) {}
    ~CACMPT_Extensions() {}

    void Delete (const std::string& oid);
    void Insert (CACMPT_Extension ext);
    iterator find( std::string oid )
    {	iterator e = end();
	for( iterator i = begin(); i != e; i++ ) 
	{ if( i->get_oid() == oid ) return i; } 
	return e;
    }
    const_iterator find( std::string oid ) const
    {	const_iterator e = end();
	for( const_iterator i = begin(); i != e; i++ ) 
	{ if( i->get_oid() == oid ) return i; }
	return e;
    }
};

enum PKIStatusEnum {
    PKI_STATUS_GRANTED,
    PKI_STATUS_GRANTEDWITHMODS,
    PKI_STATUS_REJECTION,
    PKI_STATUS_WAITING,
    PKI_STATUS_REVOCATIONWARNING,
    PKI_STATUS_REVOCATIONNOTIFICATION,
    PKI_STATUS_KEYUPDATEWARNING
};

// since we can fail in more than one way!
// More codes may be added in the future if/when required.
struct FailureInfo
{
    FailureInfo();

    // unrecognized or unsupported Algorithm Identifier
    static const unsigned badAlg;
    // integrity check failed (e.g., signature did not verify)
    static const unsigned badMessageCheck;
    // transaction not permitted or supported
    static const unsigned badRequest;
    // messageTime was not sufficiently close to the system time,
    // as defined by local policy
    static const unsigned badTime;
    // no certificate could be found matching the provided criteria
    static const unsigned badCertId;
    // the data submitted has the wrong format
    static const unsigned badDataFormat;
    // the authority indicated in the request is different from the
    // one creating the response token
    static const unsigned wrongAuthority;
    // the requester's data is incorrect (used for notary services)
    static const unsigned incorrectData;
    // when the timestamp is missing but should be there (by policy)
    static const unsigned missingTimeStamp;
    // the proof-of-possession failed
    static const unsigned badPOP;
    // the TSA's time source is not available
    static const unsigned timeNotAvailable;
    // the requested TSA policy is not supported by the TSA.
    static const unsigned unacceptedPolicy;
    // the requested extension is not supported by the TSA.
    static const unsigned unacceptedExtension;
    // the additional information requested could not be understood
    // or is not available
    static const unsigned addInfoNotAvailable;
    // the request cannot be handled due to system failure  }
    static const unsigned systemFailure;

    // последовательность масок.
    static const unsigned sequence[15];

    unsigned info;

    std::string toString() const;
    void fromString( const char* );
};

CACMPT_BigInteger MakeRandomBigInteger(HCRYPTPROV hProv, size_t size);

CACMPT_BLOB MakeHash(HCRYPTPROV hCryptProv, const CACMPT_AlgorithmIdentifier& hashAlgorithm,
		     const CACMPT_BLOB& data, HCRYPTHASH* phHash = 0);

struct CACMPT_SignerInfo
{
    unsigned version;
    CACMPT_BLOB issuer;
    CACMPT_BigInteger serialNumber;
    CACMPT_AlgorithmIdentifier signatureAlgorithm;
    CACMPT_AlgorithmIdentifier digestAlgorithm;
    CACMPT_BLOB signature;
    CACMPT_Attributes signedAttributes;
    CACMPT_Attributes unsignedAttributes;
};

typedef std::list<CACMPT_SignerInfo> CACMPT_SignerInfos;

struct CACMPT_ReasonFlags
{
    static const unsigned unused; //(0)
    static const unsigned keyCompromise; //(1)
    static const unsigned caCompromise; //(2)
    static const unsigned affiliationChanged; //(3)
    static const unsigned superseded; //(4)
    static const unsigned cessationOfOperation; //(5)
    static const unsigned certificateHold; //(6)
    static const unsigned privilegeWithdrawn; //(7)
    static const unsigned aACompromise; //(8)

    static const unsigned sequence[9];
    unsigned value;
};

class CACMPT_DistributionPointNameImpl;

class CACMPT_DistributionPointName
{
public:
    enum Type
    {
	t_fullName = 1
    };
public:
    CACMPT_DistributionPointName();
    ~CACMPT_DistributionPointName();

    CACMPT_DistributionPointName( const CACMPT_DistributionPointName& src);

    // get
    Type get_type() const;
    const CACMPT_GeneralNames* get_fullName() const;
    // set
    void set_fullName( const CACMPT_GeneralNames& fullName);
private:
    void clear();
    CACMPT_DistributionPointNameImpl* pImpl_;
};

class CACMPT_DistributionPointImpl
{
public:
    CACMPT_DistributionPointImpl() {}
    CACMPT_DistributionPointImpl( const CACMPT_DistributionPointImpl& src);
public:
    std::auto_ptr<CACMPT_DistributionPointName> distributionPoint_;
    std::auto_ptr<CACMPT_ReasonFlags> reasons_;
    std::auto_ptr<CACMPT_GeneralNames> cRLIssuer_;
};

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

    CACMPT_DistributionPoint( const CACMPT_DistributionPoint& src);
    CACMPT_DistributionPoint& operator=( const CACMPT_DistributionPoint& src);

    // get
    const CACMPT_DistributionPointName* get_distributionPoint() const;
    const CACMPT_ReasonFlags* get_reasons() const;
    const CACMPT_GeneralNames* get_cRLIssuer() const;
    // set
    void set_distributionPoint( 
	const CACMPT_DistributionPointName* distributionPoint);
    void set_reasons( const CACMPT_ReasonFlags* reasons);
    void set_cRLIssuer( const CACMPT_GeneralNames* cRLIssuer);
private:
    void clear();
    CACMPT_DistributionPointImpl* pImpl_;
};

typedef std::list<CACMPT_DistributionPoint> CACMPT_CRLDistPointsSyntax;

struct CACMPT_CertId
{
    CACMPT_GeneralName issuer;
    CACMPT_BigInteger serialNumber;
};

class CACMPT_RevAnnContent
{
public:
    CACMPT_RevAnnContent() {}
    CACMPT_RevAnnContent(
	const PKIStatusEnum& status,
	const CACMPT_CertId& certId,
	const CACMPT_Date& willBeRevokedAt,
	const CACMPT_Date& badSinceDate);
    CACMPT_RevAnnContent( const CACMPT_RevAnnContent& src);

    CACMPT_RevAnnContent& operator=( const CACMPT_RevAnnContent& src);

    CACMPT_BLOB encode() const;
    void decode( const CACMPT_BLOB& encoded);

    // get
    const PKIStatusEnum& get_status() const;
    const CACMPT_CertId& get_certId() const;
    const CACMPT_Date& get_willBeRevokedAt() const;
    const CACMPT_Date& get_badSinceDate() const;
    const CACMPT_Extensions* get_crlDetails() const;
    // set
    void set_status(const PKIStatusEnum& status);
    void set_certId(const CACMPT_CertId& certId);
    void set_willBeRevokedAt(const CACMPT_Date& willBeRevokedAt);
    void set_badSinceDate( const CACMPT_Date& badSinceDate);
    void set_crlDetails( const CACMPT_Extensions* crlDetails);
private:
    PKIStatusEnum status_;
    CACMPT_CertId certId_;
    CACMPT_Date willBeRevokedAt_;
    CACMPT_Date badSinceDate_;
    std::auto_ptr<CACMPT_Extensions> crlDetails_;
};

struct CACMPT_PublicKeyInfo {
    CACMPT_PublicKeyInfo();
    CACMPT_PublicKeyInfo( const CACMPT_PublicKeyInfo &src );

    // Строка -		ASN1T_SubjectPublicKeyInfo.ASN1T_AlgorithmIdentifier.ASN1TObjId algorithm
    char Algorithm[ 254 ];
    // Двоичный -	ASN1T_SubjectPublicKeyInfo.ASN1T_AlgorithmIdentifier.ASN1TOpenType parameters
    CACMPT_BLOB AlgorithmParameters;
    // Двоичный -	ASN1T_SubjectPublicKeyInfo.ASN1TDynBitStr subjectPublicKey
    CACMPT_BLOB PublicKey;

    bool operator==( const CACMPT_PublicKeyInfo &right ) const
    { return !strcmp( Algorithm, right.Algorithm )
	&& AlgorithmParameters == right.AlgorithmParameters
	&& PublicKey == right.PublicKey; }
    bool operator!= ( const CACMPT_PublicKeyInfo &right ) const
    { return !( *this == right ); }
    CACMPT_PublicKeyInfo &operator=( const CACMPT_PublicKeyInfo &src )
    { assign( src ); return *this; }
    void assign( const CACMPT_PublicKeyInfo &src );
};

class StoreException : public CAException
{
public:
    explicit StoreException( unsigned int err, const wchar_t *store = NULL, const char *f = NULL, int l = 0 )
	: CAException( format_store( err, store ).c_str(), f, l ) {}
private:
    static std::string format_store( unsigned int err, const wchar_t *store );
};

SUP_INLINE std::string StoreException::format_store( unsigned int err, const wchar_t *store )
{ 
    char message[512];
    sprintf( message, "Ошибка 0x%x при работе с хранилищем '%ls': ", err, store ); 
    if (!FormatMessageA (FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, 
	NULL, err, 0, message+strlen(message), 
	(DWORD)(sizeof(message)-strlen(message)), NULL))
	sprintf( message, "Ошибка 0x%x при работе с хранилищем '%ls'.", err, store ); 
    return std::string( message );
}

#define CA_STORE_EXCEPTION(name) StoreException(GetLastError(),name,__FILE__,__LINE__)

void out_RequestInfo( class RequestInfo *info );
void out_CertificateInfo( class CertificateInfo *info, bool dumpRawData = true );
void out_CrlInfo( class CrlInfo *info );
void out_RevAnnContentInfo( struct RevAnnContentInfo *info );
void out_ErrorMsgInfo( const class ErrorMsgInfo *info );
void out_FailureInfo( const FailureInfo *info );
void out_tav_list( const class CACMPT_InfoTypeAndValueList &info );

// dim 2021-feb-05: похоже, что не используется
bool operator==( const CACMPT_Name& lhs, const CACMPT_Name& rhs);
#endif /* CA_CMP_TYPES_H */
