#include "P15DODF.h"
#include "Communicator.h"

CP15DODF::CP15DODF(void)
{
	// Inicializamos las variables miembro
	m_loaded	= false;
	m_ushFileId	= 0x6005;
}

CP15DODF::~CP15DODF(void)
{
}

// Método para realizar la codificación ASN1 de objetos PKCS#11
int CP15DODF::EncodeASN1( CPKCS11Object *pObj11, byteBuffer & efEncoded )
{
	bool bObjAttrib			= 0;

	byteBuffer *bbAttribute = NULL;
	byteBuffer bbAux;

	asn_enc_rval_t ret_val;

	unsigned long ulbEncodedDataLen = 1024;

	byte *bEncodedData = new (byte[ulbEncodedDataLen]);
	memset(bEncodedData, 0x00, ulbEncodedDataLen);

	int * index		= NULL;
	int * iFileLen	= NULL;

	DataObject		 * pDataASN1Object	    = NULL;

	pDataASN1Object = (DataObject*)calloc(1,sizeof(DataObject));

	// Atributos comunes de todos los objetos P11
	// CKA_CLASS
	// CKA_TOKEN
	pDataASN1Object->commonObjectAttributes.flags = (CommonObjectFlags_t*)calloc(1,sizeof(CommonObjectFlags_t));
	pDataASN1Object->commonObjectAttributes.flags->buf = (uint8_t*)calloc(1,sizeof(uint8_t));
	pDataASN1Object->commonObjectAttributes.flags->size = 1;

	// CKA_PRIVATE
	// flags->private
	bObjAttrib = pObj11->GetAttributeBool( CKA_PRIVATE );
	CUtil::SetBit( pDataASN1Object->commonObjectAttributes.flags, CommonObjectFlags_private, bObjAttrib );

	// CKA_MODIFIABLE
	// flags->modifiable
	bObjAttrib = pObj11->GetAttributeBool( CKA_MODIFIABLE );
	CUtil::SetBit( pDataASN1Object->commonObjectAttributes.flags, CommonObjectFlags_modifiable, bObjAttrib );

	// flags->bits_unused
	pDataASN1Object->commonObjectAttributes.flags->bits_unused = 0x06;

	// Diferenciaremos si la escritura debe ser en formato ISO o CERES
	if(GetASN1Type() == ASN1TYPE_ISO)
	{
		// Codificación ASN1 ISO

		// CKA_LABEL
		bbAttribute = NULL;
		bbAttribute = pObj11->GetAttribute( CKA_LABEL );

		pDataASN1Object->commonObjectAttributes.label = (LabelCERES*)calloc(1,sizeof(LabelCERES));
		pDataASN1Object->commonObjectAttributes.label->present = LabelCERES_PR_tipoutf8string; //LabelCERES_PR_tipot61string
		if(( bbAttribute != 0 ) && ( bbAttribute->size() != 0 ))
		{
			pDataASN1Object->commonObjectAttributes.label->choice.tipoutf8string.size = bbAttribute->size();
			pDataASN1Object->commonObjectAttributes.label->choice.tipoutf8string.buf = (byte *)malloc( bbAttribute->size() );
			memset( pDataASN1Object->commonObjectAttributes.label->choice.tipoutf8string.buf, 0,
					bbAttribute->size());
			memcpy( pDataASN1Object->commonObjectAttributes.label->choice.tipoutf8string.buf, bbAttribute[0],
					bbAttribute->size());
			pDataASN1Object->commonObjectAttributes.label->present = LabelCERES_PR_tipoutf8string; //LabelCERES_PR_tipot61string
		}

		// CKA_APPLICATION
		bbAttribute = NULL;
		bbAttribute = pObj11->GetAttribute( CKA_APPLICATION );

		pDataASN1Object->classAttributes.applicationName = (LabelCERES*)calloc(1,sizeof(LabelCERES));
		pDataASN1Object->classAttributes.applicationName->present = LabelCERES_PR_tipoutf8string; //LabelCERES_PR_tipot61string
		if(( bbAttribute != 0 ) && ( bbAttribute->size() != 0 ))
		{
			pDataASN1Object->classAttributes.applicationName->choice.tipoutf8string.size = bbAttribute->size();
			pDataASN1Object->classAttributes.applicationName->choice.tipoutf8string.buf = (byte *)malloc( bbAttribute->size() );
			memset( pDataASN1Object->classAttributes.applicationName->choice.tipoutf8string.buf, 0,
					bbAttribute->size());
			memcpy( pDataASN1Object->classAttributes.applicationName->choice.tipoutf8string.buf, bbAttribute[0],
					bbAttribute->size());
			pDataASN1Object->classAttributes.applicationName->present = LabelCERES_PR_tipoutf8string; //LabelCERES_PR_tipot61string
		}
	}
	else
	{
		// Codificación ASN1 CERES

		// CKA_LABEL
		bbAttribute = NULL;
		bbAttribute = pObj11->GetAttribute( CKA_LABEL );

		pDataASN1Object->commonObjectAttributes.label = (LabelCERES*)calloc(1,sizeof(LabelCERES));
		pDataASN1Object->commonObjectAttributes.label->present = LabelCERES_PR_tipot61string; //LabelCERES_PR_tipoutf8string
		if(( bbAttribute != 0 ) && ( bbAttribute->size() != 0 ))
		{
			pDataASN1Object->commonObjectAttributes.label->choice.tipot61string.size = bbAttribute->size();
			pDataASN1Object->commonObjectAttributes.label->choice.tipot61string.buf = (byte *)malloc( bbAttribute->size() );
			memset( pDataASN1Object->commonObjectAttributes.label->choice.tipot61string.buf, 0,
					bbAttribute->size());
			memcpy( pDataASN1Object->commonObjectAttributes.label->choice.tipot61string.buf, bbAttribute[0],
					bbAttribute->size());
			pDataASN1Object->commonObjectAttributes.label->present = LabelCERES_PR_tipot61string; //LabelCERES_PR_tipoutf8string
		}

		// CKA_APPLICATION
		bbAttribute = NULL;
		bbAttribute = pObj11->GetAttribute( CKA_APPLICATION );

		pDataASN1Object->classAttributes.applicationName = (LabelCERES*)calloc(1,sizeof(LabelCERES));
		pDataASN1Object->classAttributes.applicationName->present = LabelCERES_PR_tipot61string; //LabelCERES_PR_tipoutf8string
		if(( bbAttribute != 0 ) && ( bbAttribute->size() != 0 ))
		{
			pDataASN1Object->classAttributes.applicationName->choice.tipot61string.size = bbAttribute->size();
			pDataASN1Object->classAttributes.applicationName->choice.tipot61string.buf = (byte *)malloc( bbAttribute->size() );
			memset( pDataASN1Object->classAttributes.applicationName->choice.tipot61string.buf, 0,
					bbAttribute->size());
			memcpy( pDataASN1Object->classAttributes.applicationName->choice.tipot61string.buf, bbAttribute[0],
					bbAttribute->size());
			pDataASN1Object->classAttributes.applicationName->present = LabelCERES_PR_tipot61string; //LabelCERES_PR_tipoutf8string
		}
	}

	// CKA_OBJECT_ID
	bbAttribute = NULL;
	bbAttribute = pObj11->GetAttribute( CKA_OBJECT_ID );

	pDataASN1Object->classAttributes.applicationOID = NULL;
	if(( bbAttribute != 0 ) && ( bbAttribute->size() != 0 ))
	{		
		pDataASN1Object->classAttributes.applicationOID = (OBJECT_IDENTIFIER_t*)calloc(1,sizeof(OBJECT_IDENTIFIER_t));

		pDataASN1Object->classAttributes.applicationOID->buf  = (byte *)malloc( bbAttribute->size() );
		pDataASN1Object->classAttributes.applicationOID->size = bbAttribute->size();

		memset( pDataASN1Object->classAttributes.applicationOID->buf, 0, bbAttribute->size());
		memcpy( pDataASN1Object->classAttributes.applicationOID->buf, bbAttribute[0], bbAttribute->size());
	}

	// Value--> Path
	bbAttribute = NULL;
	bbAttribute = pObj11->GetValuePath();
	if(( bbAttribute != 0 ) && ( bbAttribute->size() != 0 ))
	{
		// Si estamos trabajando sobre formatos de Path en ASCII,
		// habrá que hacer la conversión en bbAttribute.
		if( GetPathEncodingType() == PATHENC_BIN )
			// Mantenemos el formato BINARIO (ej: 0x60 0x61 0x70 0x04)
			bbAux.assign(&bbAttribute->at(0), bbAttribute->size());
		else
			// Hacemos la conversión a format ASCII (ej: "\6061\7004")
			bbAux = CUtil::PathBin2ASCII(bbAttribute[0]);

		pDataASN1Object->typeAttributes.path.buf = (byte *)malloc( bbAux.size() );
		pDataASN1Object->typeAttributes.path.size = bbAux.size();

		memset( pDataASN1Object->typeAttributes.path.buf, 0, bbAux.size());
		memcpy( pDataASN1Object->typeAttributes.path.buf, &bbAux[0], bbAux.size());
	}

	// Value--> index
	index = pObj11->GetValueIndex();
	if(index != NULL)
	{
		pDataASN1Object->typeAttributes.index = (INTEGER_t*)calloc(1,sizeof(INTEGER_t));
		pDataASN1Object->typeAttributes.index->buf = (byte *)malloc( 1 );
		pDataASN1Object->typeAttributes.index->size = 1;

		memset( pDataASN1Object->typeAttributes.index->buf, 0, 1);
		memcpy( pDataASN1Object->typeAttributes.index->buf, index, 1);
	}

	// Value--> length
	iFileLen = pObj11->GetValueLength();
	if(iFileLen != NULL)
	{
		bbAux.clear();
		bbAux.append(iFileLen[0]>>8);
		bbAux.append(iFileLen[0]%0x100);

		pDataASN1Object->typeAttributes.length = (INTEGER_t*)calloc(1,sizeof(INTEGER_t));
		pDataASN1Object->typeAttributes.length->buf = (byte *)malloc( 2 );
		pDataASN1Object->typeAttributes.length->size = 2;

		memset( pDataASN1Object->typeAttributes.length->buf, 0, 2);
		memcpy( pDataASN1Object->typeAttributes.length->buf, bbAux, bbAux.size());
	}

	// Codificamos los atributos del objeto P11 a parsear
	ret_val = der_encode_to_buffer(&asn_DEF_DataObject, pDataASN1Object, bEncodedData, ulbEncodedDataLen);

	// Liberamos la estructura anterior
	asn_DEF_DataObject.free_struct( &asn_DEF_DataObject, pDataASN1Object, 0 );

	// Comprobamos el resultado del parseo
	if(ret_val.encoded == -1)
	{
		// Liberamos la memoria reservada
		if(bEncodedData)
			delete(bEncodedData);

		// Ha ocurrido algún error
		return RC_FAIL;
	}

	// Una vez realizado el parseo copiamos la respuesta a devolver
	efEncoded.resize(ret_val.encoded);
	efEncoded.assign(bEncodedData, ret_val.encoded);

	// Liberamos la memoria reservada
	if(bEncodedData)
		delete(bEncodedData);

	return RC_OK;
}


int CP15DODF::DecodeObject( byteBuffer & dodfEntry )
{
	// Variables locales
	int nRet = 0;
	asn_dec_rval_t ret_val;
	DataObject * asn1DODF = NULL;
	CPKCS11DataObject * pDataObject = NULL;

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

	// Si la decodificación ha ido bien, rellenamos los campos de la estructura pInfo
	if( ret_val.code != RC_FAIL )
	{
		// Por defecto trabajaremos con formato ISO. Si es CERES se cambiará al detectarlo
		SetASN1Type(ASN1TYPE_ISO);

		pDataObject = new CPKCS11DataObject();

		// Atributos comunes de todos los objetos P11
		pDataObject->SetAttribute( CKA_CLASS, (ulong)CKO_DATA );
		pDataObject->SetAttribute( CKA_TOKEN, true );
		pDataObject->SetAttribute( CKA_PRIVATE,
								   CUtil::GetBit( asn1DODF->commonObjectAttributes.flags, CommonObjectFlags_private ) );
		pDataObject->SetAttribute( CKA_MODIFIABLE,
								   CUtil::GetBit( asn1DODF->commonObjectAttributes.flags, CommonObjectFlags_modifiable) );
		if(asn1DODF->commonObjectAttributes.label)
		{
			// Si el label está en formato CERES, lo dejaremos indicado
			if( asn1DODF->commonObjectAttributes.label->present == LabelCERES_PR_tipot61string )
				SetASN1Type(ASN1TYPE_CERES);

			pDataObject->SetAttribute( CKA_LABEL,
									   asn1DODF->commonObjectAttributes.label->choice.tipot61string.buf,
									   asn1DODF->commonObjectAttributes.label->choice.tipot61string.size );
		}

		// Atributos comunes de los datos: applicationName
		if( asn1DODF->classAttributes.applicationName )
		{			
			// Si el label está en formato CERES, lo dejaremos indicado
			if( asn1DODF->classAttributes.applicationName->present == LabelCERES_PR_tipot61string )
				SetASN1Type(ASN1TYPE_CERES);

			// application_Name tipo LABELCERES
			pDataObject->SetAttribute( CKA_APPLICATION,
										asn1DODF->classAttributes.applicationName->choice.tipot61string.buf,
										asn1DODF->classAttributes.applicationName->choice.tipot61string.size );
		}

		// Atributos comunes de los datos: applicationOID
		if( asn1DODF->classAttributes.applicationOID )
		{
			// applicationOID
			pDataObject->SetAttribute( CKA_OBJECT_ID,
										asn1DODF->classAttributes.applicationOID->buf,
										asn1DODF->classAttributes.applicationOID->size );
		}

		if(asn1DODF->typeAttributes.path.size > 4)
			SetPathEncodingType(PATHENC_ASCII);

		pDataObject->SetValuePath( asn1DODF->typeAttributes.path.buf,
								   asn1DODF->typeAttributes.path.size,
								   CUtil::GetInt32(asn1DODF->typeAttributes.index),
								   CUtil::GetInt32((INTEGER_t *)asn1DODF->typeAttributes.length) );

		m_P11Objects.push_back( pDataObject );

		nRet = 1;
	}

	if( asn1DODF )
	{
		asn_DEF_DataObject.free_struct( &asn_DEF_DataObject, asn1DODF, 0 );
		asn1DODF = NULL;
	}

	return nRet;

}
