#include "cryptoki.h"
#include "Communicator.h"
#include "Pkcs11Exceptions.h"
#include "SlotList.h"
#include "P15TokenInfo.h"
#include "TokenInfoT61.h"

extern SCARDCONTEXT g_hContext;
extern CSlotList & g_rSlotList;

CP15TokenInfo::CP15TokenInfo(void)
{
	// Inicializamos las variables miembro
	m_loaded		= false;
	m_asn1TokenInfo = NULL;
	m_ushFileId		= 0x5032;
}

CP15TokenInfo::~CP15TokenInfo(void)
{
	Erase();
}

void CP15TokenInfo::Erase(void)
{
	if( m_asn1TokenInfo )
	{
		asn_DEF_TokenInfo.free_struct( &asn_DEF_TokenInfo, m_asn1TokenInfo, 0 );
		m_asn1TokenInfo = NULL;
	}

	m_loaded = false;
}


// Método para codificar una cadena de bytes y convertirla a formato ASN1
int CP15TokenInfo::EncodeASN1(void)
{
	// Variables locales
	TokenInfo bTIejemplo;
	asn_enc_rval_t ret_val;
	//asn_app_consume_bytes_f asnEstruc;
	char buffer[256];
	char bufferEj[256];
	memset(buffer, 0x00, 256);
	memset(bufferEj, 0x00, 256);
	char serial[7] = {0x06,0x63,0x55,0x03,0x01,0x5A,0x4D};
	char version[1] = {0x00};
	char options[1] = {0x60};

	bTIejemplo.serialNumber.buf		= (uint8_t *)serial;
	bTIejemplo.serialNumber.size	= 7;

	//bTIejemplo.version.buf			= NULL;
	bTIejemplo.version.buf			= (uint8_t *)version;
	bTIejemplo.version.size			= 1;

	bTIejemplo.tokenflags.buf		= (uint8_t *)options;
	bTIejemplo.tokenflags.bits_unused	= 4;
	bTIejemplo.tokenflags.size		= 1;

	bTIejemplo._asn_ctx.context	= 0;
	bTIejemplo._asn_ctx.left	= 0;
	bTIejemplo._asn_ctx.phase	= 0;
	bTIejemplo._asn_ctx.ptr		= NULL;
	bTIejemplo._asn_ctx.step	= 0;

	// Ejemplo de codificación:
	ret_val = der_encode_to_buffer(&asn_DEF_TokenInfo, &bTIejemplo, bufferEj, 256);
	if(ret_val.encoded == -1)
	{
		// Ha ocurrido algún error
		return (int)ret_val.encoded;
	}

	// Codificación ASN1 a partir la variable miembro m_asn1TokenInfo
	ret_val = der_encode_to_buffer(&asn_DEF_TokenInfo, m_asn1TokenInfo, buffer, 256);

	if(ret_val.encoded == -1)
	{
		// Ha ocurrido algún error
		return (int)ret_val.encoded;
	}
	else
		return 0;

}


// Función para rellenar el contenido del puntero a la estructura CK_TOKEN_INFO
int CP15TokenInfo::LoadTokenInfo(CK_TOKEN_INFO_PTR pInfo)
{
	// Inicializamos la estructura pInfo
	pInfo->hardwareVersion.major = 0x00;
	pInfo->hardwareVersion.minor = 0x00;
	pInfo->firmwareVersion.major = 0x00;
	pInfo->firmwareVersion.minor = 0x00;

	memset(pInfo->serialNumber,		0x20, sizeof(pInfo->serialNumber));
	memset(pInfo->model,			0x20, sizeof(pInfo->model));
	memset(pInfo->manufacturerID,	0x20, sizeof(pInfo->manufacturerID));
	memset(pInfo->label,			0x20, sizeof(pInfo->label));
	pInfo->flags				= 0;
	pInfo->ulMaxSessionCount	= 0;
	pInfo->ulSessionCount		= 0;
	pInfo->ulMaxRwSessionCount	= 0;
	pInfo->ulRwSessionCount		= 0;
	pInfo->ulMaxPinLen			= 16;
	pInfo->ulMinPinLen			= 4;
	pInfo->ulTotalPublicMemory	= 0;
	pInfo->ulFreePublicMemory	= 0;
	pInfo->ulTotalPrivateMemory	= 0;
	pInfo->ulFreePrivateMemory	= 0;

	// Si no tenemos cargada la estructura TokenInfo, devolveremos un error.
	if( !m_asn1TokenInfo )
		return 0;

	// Copiamos el contenido del atributo Version
	pInfo->hardwareVersion.major = m_asn1TokenInfo->version.buf[0];

	// Copiamos el contenido del atributo Serial Number
	// TODO: decidir si devolvemos el serialNumber en ASCII o en BINARIO (23-02-2012)
	CUtil::Bin2ASCII(m_asn1TokenInfo->serialNumber.buf, m_asn1TokenInfo->serialNumber.size, (char*)&pInfo->serialNumber);
	//memcpy(pInfo->serialNumber, m_asn1TokenInfo->serialNumber.buf, m_asn1TokenInfo->serialNumber.size);

	// Copiamos el contenido del atributo Manufacturer
	memcpy(pInfo->manufacturerID, m_asn1TokenInfo->manufacturerID.buf, m_asn1TokenInfo->manufacturerID.size);

	// Copiamos el contenido del atributo Label
	memcpy(pInfo->label, m_asn1TokenInfo->label.buf, m_asn1TokenInfo->label.size);

	// Copiamos el contenido del atributo Flags
	pInfo->flags = (CK_FLAGS)(((m_asn1TokenInfo->tokenflags.buf[0]&0x80)?CKF_WRITE_PROTECTED:0) |
							  ((m_asn1TokenInfo->tokenflags.buf[0]&0x40)?CKF_LOGIN_REQUIRED:0) |
							  ((m_asn1TokenInfo->tokenflags.buf[0]&0x20)?CKF_RNG:0) |
							  CKF_USER_PIN_INITIALIZED | CKF_TOKEN_INITIALIZED );

	return 1;
}


int CP15TokenInfo::DecodeObject(byteBuffer & tokenInfoData)
{
	// Variables locales
	int nRet = 0;
	asn_dec_rval_t ret_val;

	TokenInfoT61 * asn1TokenInfoT61 = NULL;

	// Si teníamos información previa del TokenInfo, la eliminamos
	if( m_asn1TokenInfo )
		Erase();

	// Realizamos la decodificación BER de los datos miembros
	ret_val = ber_decode( NULL,
						  &asn_DEF_TokenInfo,
						  (void**)&m_asn1TokenInfo,
						  (void*)&tokenInfoData[0],
						  tokenInfoData.size() );

	if(ret_val.code == RC_OK)
		nRet = 1;
	else
	{

		//
		// Ha fallado la decodificación del TokenInfo según el estandar.
		// Liberamos la memoria de la estructura antes de probar con otras ...
		//
		if ( m_asn1TokenInfo )
			Erase();

		//
		// Probamos a decodificar con la estructura de las tarjetas CERES <= antiguas
		// Usamos la estructura TokenInfoT61
		//
		ret_val = ber_decode( NULL,
							  &asn_DEF_TokenInfoT61,
							  (void**)&asn1TokenInfoT61,
							  (void*)&tokenInfoData[0],
							  tokenInfoData.size() );

		//
		// Si fue bien copiamos los campos a la estructura estandar
		//
		if( ret_val.code == RC_OK )
		{
			m_asn1TokenInfo					= (TokenInfo*)calloc(1,sizeof(TokenInfo));

			m_asn1TokenInfo->version.buf	= (byte *)malloc( asn1TokenInfoT61->version.size );
			m_asn1TokenInfo->version.size	= asn1TokenInfoT61->version.size;
			memcpy( m_asn1TokenInfo->version.buf,
					asn1TokenInfoT61->version.buf,
					asn1TokenInfoT61->version.size );

			OCTET_STRING_fromBuf( &(m_asn1TokenInfo->serialNumber),
								  (const char *)asn1TokenInfoT61->serialNumber.buf,
								  asn1TokenInfoT61->serialNumber.size );
			OCTET_STRING_fromBuf( &(m_asn1TokenInfo->manufacturerID),
								  (const char *)asn1TokenInfoT61->manufacturerID.buf,
								  asn1TokenInfoT61->manufacturerID.size );
			OCTET_STRING_fromBuf( &(m_asn1TokenInfo->label),
								  (const char *)asn1TokenInfoT61->label.buf,
								  asn1TokenInfoT61->label.size );

			m_asn1TokenInfo->tokenflags.buf = (byte *)malloc( asn1TokenInfoT61->tokenflags.size );
			memcpy( m_asn1TokenInfo->tokenflags.buf,
					asn1TokenInfoT61->tokenflags.buf,
					asn1TokenInfoT61->tokenflags.size );
			m_asn1TokenInfo->tokenflags.size = asn1TokenInfoT61->tokenflags.size;
			m_asn1TokenInfo->tokenflags.bits_unused = asn1TokenInfoT61->tokenflags.bits_unused;

			nRet = 1;
		}

		if ( asn1TokenInfoT61 )
		{
			asn_DEF_TokenInfoT61.free_struct( &asn_DEF_TokenInfoT61, asn1TokenInfoT61, 0 );
			asn1TokenInfoT61 = NULL;
		}

	}

	return nRet;

}
