#include <winscard.h>

#include "cryptoki.h"
#include "SlotList.h"
#include "Pkcs11Exceptions.h"
#include "P15PuKDF.h"
#include "Communicator.h"
#include "PublicKeyObjectCERES.h"

extern SCARDCONTEXT g_hContext;
extern CSlotList &g_rSlotList;

CP15PuKDF::CP15PuKDF(void)
{
	// Inicializamos las variables miembro
	m_loaded	= false;
	m_ushFileId	= 0x6002;

}

CP15PuKDF::~CP15PuKDF(void)
{
}


// Método para codificar un objeto PKCS#11 y convertirlo a formato ASN1
int CP15PuKDF::EncodeASN1( CPKCS11Object *pObj11, byteBuffer & efEncoded )
{
	bool bObjAttrib		 = 0;

	byteBuffer *bbAttribute = NULL;
	byteBuffer bbAux;

	byte bKeyRef		= 0x00;

	asn_enc_rval_t ret_val;

	unsigned long ulEncodedPubKLen = 1024;
	byte *bEncodedPubK = new (byte[ulEncodedPubKLen]);

	memset(bEncodedPubK, 0x00, ulEncodedPubKLen);

	int * index			 = NULL;
	int * iFileLen		 = NULL;
	CK_ULONG ulKeyLen	 = 0;

	PublicKeyObject		 * pPubKeyASN1Object	  = NULL;
	PublicKeyObjectCERES * pPubKeyASN1ObjectCeres = NULL;

	// Diferenciaremos si la escritura debe ser en formato ISO o CERES
	//if(m_asn1Type == ASN1TYPE_ISO)
	if(GetASN1Type() == ASN1TYPE_ISO)
	{
		// Codificación ASN1 ISO
		pPubKeyASN1Object = (PublicKeyObject*)calloc(1,sizeof(PublicKeyObject));

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

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

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

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

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

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

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

		if(( bbAttribute != 0 ) && ( bbAttribute->size() != 0 ))
		{
			pPubKeyASN1Object->classAttributes.iD.buf  = (byte *)malloc( bbAttribute->size() );
			pPubKeyASN1Object->classAttributes.iD.size = bbAttribute->size();

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

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

		// A la hora de codificar esto añade la entrada "A0 00" si no existe SUBJECT,
		// necesario por compatiblidad con drivers antiguos
		pPubKeyASN1Object->subClassAttributes = (ANY_t*)calloc(1,sizeof(ANY_t));
		if(( bbAttribute != 0 ) && ( bbAttribute->size() != 0 ))
		{
			pPubKeyASN1Object->subClassAttributes->buf  = (byte *)malloc( bbAttribute->size() );
			pPubKeyASN1Object->subClassAttributes->size = bbAttribute->size();

			memset( pPubKeyASN1Object->subClassAttributes->buf, 0, bbAttribute->size());
			memcpy( pPubKeyASN1Object->subClassAttributes->buf, bbAttribute[0], bbAttribute->size());
		}

		// classAtributes.usage
		pPubKeyASN1Object->classAttributes.usage.buf = (uint8_t*)calloc(2,sizeof(uint8_t));
		pPubKeyASN1Object->classAttributes.usage.size = 2;

		// CKA_ENCRYPT
		bObjAttrib = pObj11->GetAttributeBool( CKA_ENCRYPT );
		CUtil::SetBit( &pPubKeyASN1Object->classAttributes.usage, KeyUsageFlags_encrypt, bObjAttrib );

		// CKA_VERIFY
		bObjAttrib = pObj11->GetAttributeBool( CKA_VERIFY );
		CUtil::SetBit( &pPubKeyASN1Object->classAttributes.usage, KeyUsageFlags_verify, bObjAttrib );

		// CKA_VERIFY_RECOVER
		bObjAttrib = pObj11->GetAttributeBool( CKA_VERIFY_RECOVER );
		CUtil::SetBit( &pPubKeyASN1Object->classAttributes.usage, KeyUsageFlags_verifyRecover, bObjAttrib );

		// CKA_WRAP
		bObjAttrib = pObj11->GetAttributeBool( CKA_WRAP );
		CUtil::SetBit( &pPubKeyASN1Object->classAttributes.usage, KeyUsageFlags_wrap, bObjAttrib );

		/*// CKA_DECRYPT
		bObjAttrib = pObj11->GetAttributeBool( CKA_DECRYPT );
		CUtil::SetBit( &pPubKeyASN1Object->classAttributes.usage, KeyUsageFlags_decrypt, bObjAttrib );

		// CKA_SIGN
		bObjAttrib = pObj11->GetAttributeBool( CKA_SIGN );
		CUtil::SetBit( &pPubKeyASN1Object->classAttributes.usage, KeyUsageFlags_sign, bObjAttrib );

		// CKA_SIGN_RECOVER
		bObjAttrib = pObj11->GetAttributeBool( CKA_SIGN_RECOVER );
		CUtil::SetBit( &pPubKeyASN1Object->classAttributes.usage, KeyUsageFlags_signRecover, bObjAttrib );

		// CKA_UNWRAP
		bObjAttrib = pObj11->GetAttributeBool( CKA_UNWRAP );
		CUtil::SetBit( &pPubKeyASN1Object->classAttributes.usage, KeyUsageFlags_unwrap, bObjAttrib );*/

		// CKA_DERIVE
		bObjAttrib = pObj11->GetAttributeBool( CKA_DERIVE );
		CUtil::SetBit( &pPubKeyASN1Object->classAttributes.usage, KeyUsageFlags_derive, bObjAttrib );

		// CKA_VD_NONREPUDIATION (nuestro atributo P11 propietario para mantener el No Repudio del KeyUsage.
		try
		{
			bObjAttrib = pObj11->GetAttributeBool( CKA_VD_NONREPUDIATION );
			CUtil::SetBit( &pPubKeyASN1Object->classAttributes.usage, KeyUsageFlags_nonRepudiation, bObjAttrib );
		}
		catch(Pkcs11Exception)
		{
			// Si no hay atributo CKA_VD_NONREPUDIATION no lo incluimos en el PKCS15
		}

		// usage->bits_unused
		pPubKeyASN1Object->classAttributes.usage.bits_unused = 0x06;

		// classAttributes.native
		pPubKeyASN1Object->classAttributes.native = true;

		// classAttributes.accessFlags
		pPubKeyASN1Object->classAttributes.accessFlags = (KeyAccessFlags_t*)calloc(1,sizeof(KeyAccessFlags_t));
		pPubKeyASN1Object->classAttributes.accessFlags->buf = (uint8_t*)calloc(1,sizeof(uint8_t));
		pPubKeyASN1Object->classAttributes.accessFlags->size = 1;
		pPubKeyASN1Object->classAttributes.accessFlags->bits_unused = 3;

		/*// classAttributes.accessFlags->sensitive
		bObjAttrib = pObj11->GetAttributeBool( CKA_SENSITIVE );
		CUtil::SetBit( pPubKeyASN1Object->classAttributes.accessFlags, KeyAccessFlags_sensitive, bObjAttrib );

		// classAttributes.accessFlags->extractable
		bObjAttrib = pObj11->GetAttributeBool( CKA_EXTRACTABLE );
		CUtil::SetBit( pPubKeyASN1Object->classAttributes.accessFlags, KeyAccessFlags_extractable, bObjAttrib );

		// classAttributes.accessFlags->alwaysSensitive
		bObjAttrib = pObj11->GetAttributeBool( CKA_ALWAYS_SENSITIVE );
		CUtil::SetBit( pPubKeyASN1Object->classAttributes.accessFlags, KeyAccessFlags_alwaysSensitive, bObjAttrib );

		// classAttributes.accessFlags->neverExtractable
		bObjAttrib = pObj11->GetAttributeBool( CKA_NEVER_EXTRACTABLE );
		CUtil::SetBit( pPubKeyASN1Object->classAttributes.accessFlags, KeyAccessFlags_neverExtractable, bObjAttrib );*/

		// classAttributes.accessFlags->local
		bObjAttrib = pObj11->GetAttributeBool( CKA_LOCAL );
		CUtil::SetBit( pPubKeyASN1Object->classAttributes.accessFlags, KeyAccessFlags_local, bObjAttrib );

		// classAttributes.keyReference
		bKeyRef = ((CPKCS11KeyObject*)pObj11)->GetKeyReference();
		pPubKeyASN1Object->classAttributes.keyReference.buf = (uint8_t *)calloc(1,sizeof(uint8_t));
		pPubKeyASN1Object->classAttributes.keyReference.size = 1;

		memset( pPubKeyASN1Object->classAttributes.keyReference.buf, 0, 1);
		memcpy( pPubKeyASN1Object->classAttributes.keyReference.buf, &bKeyRef, 1);

		// classAttributes.startDate
		bbAttribute = NULL;
		bbAttribute = pObj11->GetAttribute( CKA_START_DATE );
		if(( bbAttribute != 0 ) && ( bbAttribute->size() != 0 ))
		{
			pPubKeyASN1Object->classAttributes.startDate->buf  = (byte *)malloc( bbAttribute->size() );
			pPubKeyASN1Object->classAttributes.startDate->size = bbAttribute->size();

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

		// classAttributes.endDate
		bbAttribute = NULL;
		bbAttribute = pObj11->GetAttribute( CKA_END_DATE );
		if(( bbAttribute != 0 ) && ( bbAttribute->size() != 0 ))
		{
			pPubKeyASN1Object->classAttributes.endDate->buf  = (byte *)malloc( bbAttribute->size() );
			pPubKeyASN1Object->classAttributes.endDate->size = bbAttribute->size();

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

		// typeAttributes.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]);

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

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

		}

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

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

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

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

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

		// typeAttributes.modulusLength
		ulKeyLen = ((CPKCS11KeyObject*)pObj11)->GetKeyLen();
		if(ulKeyLen != 0)
		{
			bbAux.clear();
			bbAux.append((byte)(ulKeyLen>>8));
			bbAux.append((byte)(ulKeyLen%0x100));

			pPubKeyASN1Object->typeAttributes.modulusLength.buf = (byte *)malloc( 2 );
			pPubKeyASN1Object->typeAttributes.modulusLength.size = 2;

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

		// Codificamos los atributos del objeto P11 a parsear
		ret_val = der_encode_to_buffer(&asn_DEF_PublicKeyObject, pPubKeyASN1Object, bEncodedPubK, ulEncodedPubKLen);

		// Liberamos la estructura anterior
		asn_DEF_PublicKeyObject.free_struct( &asn_DEF_PublicKeyObject, pPubKeyASN1Object, 0 );
	}
	else
	{
		// Codificación ASN1 CERES
		pPubKeyASN1ObjectCeres = (PublicKeyObjectCERES*)calloc(1,sizeof(PublicKeyObjectCERES));

		// Atributos comunes de todos los objetos P11
		// CKA_CLASS
		// CKA_TOKEN

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

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

		// flags:
		pPubKeyASN1ObjectCeres->commonObjectAttributes.flags = (CommonObjectFlags_t*)calloc(1,sizeof(CommonObjectFlags_t));
		pPubKeyASN1ObjectCeres->commonObjectAttributes.flags->buf = (uint8_t*)calloc(1,sizeof(uint8_t));
		pPubKeyASN1ObjectCeres->commonObjectAttributes.flags->size = 1;

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

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

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

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

		if(( bbAttribute != 0 ) && ( bbAttribute->size() != 0 ))
		{
			pPubKeyASN1ObjectCeres->classAttributes.iD.buf  = (byte *)malloc( bbAttribute->size() );
			pPubKeyASN1ObjectCeres->classAttributes.iD.size = bbAttribute->size();

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

		// typeAttributes.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]);

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

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

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

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

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

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

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

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

		// A la hora de codificar esto añade la entrada "A0 00" si no existe SUBJECT,
		// necesario por compatiblidad con drivers antiguos
		pPubKeyASN1ObjectCeres->subClassAttributes = (ANY_t*)calloc(1,sizeof(ANY_t));
		if(( bbAttribute != 0 ) && ( bbAttribute->size() != 0 ))
		{
			pPubKeyASN1ObjectCeres->subClassAttributes->buf  = (byte *)malloc( bbAttribute->size() );
			pPubKeyASN1ObjectCeres->subClassAttributes->size = bbAttribute->size();

			memset( pPubKeyASN1ObjectCeres->subClassAttributes->buf, 0, bbAttribute->size());
			memcpy( pPubKeyASN1ObjectCeres->subClassAttributes->buf, bbAttribute[0], bbAttribute->size());
		}

		pPubKeyASN1ObjectCeres->classAttributes.usage.buf = (uint8_t*)calloc(2,sizeof(uint8_t));
		pPubKeyASN1ObjectCeres->classAttributes.usage.size = 2;

		// CKA_ENCRYPT
		bObjAttrib = pObj11->GetAttributeBool( CKA_ENCRYPT );
		CUtil::SetBit( &pPubKeyASN1ObjectCeres->classAttributes.usage, KeyUsageFlags_encrypt, bObjAttrib );

		// CKA_VERIFY
		bObjAttrib = pObj11->GetAttributeBool( CKA_VERIFY );
		CUtil::SetBit( &pPubKeyASN1ObjectCeres->classAttributes.usage, KeyUsageFlags_verify, bObjAttrib );

		// CKA_VERIFY_RECOVER
		bObjAttrib = pObj11->GetAttributeBool( CKA_VERIFY_RECOVER );
		CUtil::SetBit( &pPubKeyASN1ObjectCeres->classAttributes.usage, KeyUsageFlags_verifyRecover, bObjAttrib );

		// CKA_WRAP
		bObjAttrib = pObj11->GetAttributeBool( CKA_WRAP );
		CUtil::SetBit( &pPubKeyASN1ObjectCeres->classAttributes.usage, KeyUsageFlags_wrap, bObjAttrib );

		/*// CKA_DECRYPT
		bObjAttrib = pObj11->GetAttributeBool( CKA_DECRYPT );
		CUtil::SetBit( &pPubKeyASN1ObjectCeres->classAttributes.usage, KeyUsageFlags_decrypt, bObjAttrib );

		// CKA_SIGN
		bObjAttrib = pObj11->GetAttributeBool( CKA_SIGN );
		CUtil::SetBit( &pPubKeyASN1ObjectCeres->classAttributes.usage, KeyUsageFlags_sign, bObjAttrib );

		// CKA_SIGN_RECOVER
		bObjAttrib = pObj11->GetAttributeBool( CKA_SIGN_RECOVER );
		CUtil::SetBit( &pPubKeyASN1ObjectCeres->classAttributes.usage, KeyUsageFlags_signRecover, bObjAttrib );

		// CKA_UNWRAP
		bObjAttrib = pObj11->GetAttributeBool( CKA_UNWRAP );
		CUtil::SetBit( &pPubKeyASN1ObjectCeres->classAttributes.usage, KeyUsageFlags_unwrap, bObjAttrib );*/

		// CKA_DERIVE
		bObjAttrib = pObj11->GetAttributeBool( CKA_DERIVE );
		CUtil::SetBit( &pPubKeyASN1ObjectCeres->classAttributes.usage, KeyUsageFlags_derive, bObjAttrib );

		// CKA_VD_NONREPUDIATION (nuestro atributo P11 propietario para mantener el No Repudio del KeyUsage.
		try
		{
			bObjAttrib = pObj11->GetAttributeBool( CKA_VD_NONREPUDIATION );
			CUtil::SetBit( &pPubKeyASN1ObjectCeres->classAttributes.usage, KeyUsageFlags_nonRepudiation, bObjAttrib );
		}
		catch(Pkcs11Exception)
		{
			// Si no hay atributo CKA_VD_NONREPUDIATION no lo incluimos en el PKCS15
		}

		// usage->bits_unused
		pPubKeyASN1ObjectCeres->classAttributes.usage.bits_unused = 0x06;

		// classAttributes.native
		pPubKeyASN1ObjectCeres->classAttributes.native = true;

		// classAttributes.accessFlags
		pPubKeyASN1ObjectCeres->classAttributes.accessFlags = (KeyAccessFlags_t*)calloc(1,sizeof(KeyAccessFlags_t));
		pPubKeyASN1ObjectCeres->classAttributes.accessFlags->buf = (uint8_t*)calloc(1,sizeof(uint8_t));
		pPubKeyASN1ObjectCeres->classAttributes.accessFlags->size = 1;
		pPubKeyASN1ObjectCeres->classAttributes.accessFlags->bits_unused = 3;

		/*// classAttributes.accessFlags->sensitive
		bObjAttrib = pObj11->GetAttributeBool( CKA_SENSITIVE );
		CUtil::SetBit( pPubKeyASN1ObjectCeres->classAttributes.accessFlags, KeyAccessFlags_sensitive, bObjAttrib );

		// classAttributes.accessFlags->extractable
		bObjAttrib = pObj11->GetAttributeBool( CKA_EXTRACTABLE );
		CUtil::SetBit( pPubKeyASN1ObjectCeres->classAttributes.accessFlags, KeyAccessFlags_extractable, bObjAttrib );

		// classAttributes.accessFlags->alwaysSensitive
		bObjAttrib = pObj11->GetAttributeBool( CKA_ALWAYS_SENSITIVE );
		CUtil::SetBit( pPubKeyASN1ObjectCeres->classAttributes.accessFlags, KeyAccessFlags_alwaysSensitive, bObjAttrib );

		// classAttributes.accessFlags->neverExtractable
		bObjAttrib = pObj11->GetAttributeBool( CKA_NEVER_EXTRACTABLE );
		CUtil::SetBit( pPubKeyASN1ObjectCeres->classAttributes.accessFlags, KeyAccessFlags_neverExtractable, bObjAttrib );*/

		// classAttributes.accessFlags->local
		bObjAttrib = pObj11->GetAttributeBool( CKA_LOCAL );
		CUtil::SetBit( pPubKeyASN1ObjectCeres->classAttributes.accessFlags, KeyAccessFlags_local, bObjAttrib );

		// classAttributes.keyReference
		bKeyRef = ((CPKCS11KeyObject*)pObj11)->GetKeyReference();
		pPubKeyASN1ObjectCeres->classAttributes.keyReference.buf = (uint8_t *)calloc(1,sizeof(uint8_t));
		pPubKeyASN1ObjectCeres->classAttributes.keyReference.size = 1;

		memset( pPubKeyASN1ObjectCeres->classAttributes.keyReference.buf, 0, 1);
		memcpy( pPubKeyASN1ObjectCeres->classAttributes.keyReference.buf, &bKeyRef, 1);

		// classAttributes.startDate
		bbAttribute = NULL;
		bbAttribute = pObj11->GetAttribute( CKA_START_DATE );
		if(( bbAttribute != 0 ) && ( bbAttribute->size() != 0 ))
		{
			pPubKeyASN1ObjectCeres->classAttributes.startDate->buf  = (byte *)malloc( bbAttribute->size() );
			pPubKeyASN1ObjectCeres->classAttributes.startDate->size = bbAttribute->size();

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

		// classAttributes.endDate
		bbAttribute = NULL;
		bbAttribute = pObj11->GetAttribute( CKA_END_DATE );
		if(( bbAttribute != 0 ) && ( bbAttribute->size() != 0 ))
		{
			pPubKeyASN1ObjectCeres->classAttributes.endDate->buf  = (byte *)malloc( bbAttribute->size() );
			pPubKeyASN1ObjectCeres->classAttributes.endDate->size = bbAttribute->size();

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

		// typeAttributes.modulusLength
		ulKeyLen = ((CPKCS11KeyObject*)pObj11)->GetKeyLen();
		if(ulKeyLen != 0)
		{
			bbAux.clear();
			bbAux.append((byte)(ulKeyLen>>8));
			bbAux.append((byte)(ulKeyLen%0x100));

			pPubKeyASN1ObjectCeres->typeAttributes.modulusLength.buf = (byte *)malloc( 2 );
			pPubKeyASN1ObjectCeres->typeAttributes.modulusLength.size = 2;

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

		// Codificamos los atributos del objeto P11 a parsear
		ret_val = der_encode_to_buffer(&asn_DEF_PublicKeyObjectCERES, pPubKeyASN1ObjectCeres, bEncodedPubK, ulEncodedPubKLen);

		// Liberamos la estructura anterior
		asn_DEF_PublicKeyObjectCERES.free_struct( &asn_DEF_PublicKeyObjectCERES, pPubKeyASN1ObjectCeres, 0 );
	}

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

		// Ha ocurrido algún error
		return (int)ret_val.encoded;
	}

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

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

	return RC_OK;
}


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

	PublicKeyObject * asn1PUKDF = NULL;
	PublicKeyObjectCERES * asn1PUKDFCeres = NULL;

	CPKCS11PublicKeyObject * pPublicKeyObject = NULL;

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

	if( ret_val.code == RC_OK )
	{
		// Dejaremos indicado que la codificación de este fichero es tipo ISO
		//m_asn1Type = ASN1TYPE_ISO;
		SetASN1Type(ASN1TYPE_ISO);

		pPublicKeyObject = new CPKCS11PublicKeyObject();

		// Atributos comunes de todos los objetos P11
		pPublicKeyObject->SetAttribute( CKA_PRIVATE,
										CUtil::GetBit( asn1PUKDF->commonObjectAttributes.flags, CommonObjectFlags_private ) );
		pPublicKeyObject->SetAttribute( CKA_MODIFIABLE,
										CUtil::GetBit( asn1PUKDF->commonObjectAttributes.flags, CommonObjectFlags_modifiable ) );
		if(asn1PUKDF->commonObjectAttributes.label)
		{
			pPublicKeyObject->SetAttribute( CKA_LABEL,
											asn1PUKDF->commonObjectAttributes.label->choice.tipoutf8string.buf,
											asn1PUKDF->commonObjectAttributes.label->choice.tipoutf8string.size );
		}

		// Atributos comunes de claves
		pPublicKeyObject->SetAttribute( CKA_KEY_TYPE, (ulong)CKK_RSA);
		pPublicKeyObject->SetAttribute( CKA_ID,
										asn1PUKDF->classAttributes.iD.buf,
										asn1PUKDF->classAttributes.iD.size);
		pPublicKeyObject->SetAttribute( CKA_DERIVE,
										CUtil::GetBit( &asn1PUKDF->classAttributes.usage, KeyUsageFlags_derive ) );
		pPublicKeyObject->SetAttribute( CKA_LOCAL,
										CUtil::GetBit( asn1PUKDF->classAttributes.accessFlags, KeyAccessFlags_local ) );

		if(asn1PUKDF->classAttributes.startDate)
		{
			pPublicKeyObject->SetAttribute( CKA_START_DATE,
											 asn1PUKDF->classAttributes.startDate->buf,
											 asn1PUKDF->classAttributes.startDate->size );
		}

		if(asn1PUKDF->classAttributes.endDate)
		{
			pPublicKeyObject->SetAttribute( CKA_END_DATE,
											 asn1PUKDF->classAttributes.endDate->buf,
											 asn1PUKDF->classAttributes.endDate->size );
		}

		// Atributos de claves públicas
		if(asn1PUKDF->subClassAttributes)
		{
			pPublicKeyObject->SetAttribute( CKA_SUBJECT,
											asn1PUKDF->subClassAttributes->buf,
											asn1PUKDF->subClassAttributes->size );
		}
		pPublicKeyObject->SetAttribute( CKA_ENCRYPT,
										CUtil::GetBit( &asn1PUKDF->classAttributes.usage, KeyUsageFlags_encrypt ) );
		pPublicKeyObject->SetAttribute( CKA_VERIFY,
										CUtil::GetBit( &asn1PUKDF->classAttributes.usage, KeyUsageFlags_verify ) );
		pPublicKeyObject->SetAttribute( CKA_VERIFY_RECOVER,
										CUtil::GetBit( &asn1PUKDF->classAttributes.usage, KeyUsageFlags_verifyRecover ) );
		pPublicKeyObject->SetAttribute( CKA_WRAP,
										CUtil::GetBit( &asn1PUKDF->classAttributes.usage, KeyUsageFlags_wrap ) );

		// Resto de atributos para inicialización de flags PKCS#15
		pPublicKeyObject->SetAttribute( CKA_DECRYPT,
										CUtil::GetBit( &asn1PUKDF->classAttributes.usage, KeyUsageFlags_decrypt ) );
		pPublicKeyObject->SetAttribute( CKA_SIGN,
										CUtil::GetBit( &asn1PUKDF->classAttributes.usage, KeyUsageFlags_sign ) );
		pPublicKeyObject->SetAttribute( CKA_SIGN_RECOVER,
										CUtil::GetBit( &asn1PUKDF->classAttributes.usage, KeyUsageFlags_signRecover ) );
		pPublicKeyObject->SetAttribute( CKA_UNWRAP,
										CUtil::GetBit( &asn1PUKDF->classAttributes.usage, KeyUsageFlags_unwrap ) );
		
		// Nos creamos un atributo propio para mantener el NO REPUDIO del KeyUsage
		pPublicKeyObject->SetAttribute( CKA_VD_NONREPUDIATION,
			CUtil::GetBit( &asn1PUKDF->classAttributes.usage,KeyUsageFlags_nonRepudiation) );

		pPublicKeyObject->SetAttribute( CKA_SENSITIVE,
										CUtil::GetBit( asn1PUKDF->classAttributes.accessFlags, KeyAccessFlags_sensitive ) );
		pPublicKeyObject->SetAttribute( CKA_EXTRACTABLE,
										CUtil::GetBit( asn1PUKDF->classAttributes.accessFlags, KeyAccessFlags_extractable ) );
		pPublicKeyObject->SetAttribute( CKA_ALWAYS_SENSITIVE,
										CUtil::GetBit( asn1PUKDF->classAttributes.accessFlags, KeyAccessFlags_alwaysSensitive ) );
		pPublicKeyObject->SetAttribute( CKA_NEVER_EXTRACTABLE,
										CUtil::GetBit( asn1PUKDF->classAttributes.accessFlags, KeyAccessFlags_neverExtractable ) );
 		
		pPublicKeyObject->SetAttribute( CKA_MODULUS_BITS,
										(ulong)CUtil::GetInt32( &asn1PUKDF->typeAttributes.modulusLength ) );

		// Parámetros del PKCS#15
		pPublicKeyObject->SetKeyReference( CUtil::GetInt32( &asn1PUKDF->classAttributes.keyReference ) );
		pPublicKeyObject->SetKeyLen((ulong)CUtil::GetInt32( &asn1PUKDF->typeAttributes.modulusLength) );

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

		pPublicKeyObject->SetValuePath( asn1PUKDF->typeAttributes.value.path.buf,
										asn1PUKDF->typeAttributes.value.path.size,
										CUtil::GetInt32( asn1PUKDF->typeAttributes.value.index ),
										CUtil::GetInt32( (INTEGER_t *)asn1PUKDF->typeAttributes.value.length ) );

		m_P11Objects.push_back( pPublicKeyObject );

		if( asn1PUKDF )
		{
			asn_DEF_PublicKeyObject.free_struct(&asn_DEF_PublicKeyObject, asn1PUKDF, 0);
			asn1PUKDF = NULL;
		}

		// Fin del parseo PKCS#15 estándar
		return 1;
	}

	if(asn1PUKDF)
	{
		// Liberamos la estructura anterior
		asn_DEF_PublicKeyObject.free_struct( &asn_DEF_PublicKeyObject, asn1PUKDF, 0 );
		asn1PUKDF = NULL;
	}

	// Una vez realizado el cambio intentaremos parsear de nuevo el PuKDF y la estructura Ceres
	ret_val = ber_decode( NULL,
						  &asn_DEF_PublicKeyObjectCERES,
						  (void**)&asn1PUKDFCeres,
						  (void*)&pukdfEntry[0],
						  pukdfEntry.size() );

	// Si la decodificación ha ido bien, rellenamos los campos de la estructura pInfo
	if( ret_val.code != RC_FAIL )
	{
		// Dejaremos indicado que la codificación de este fichero es tipo ISO
		//m_asn1Type = ASN1TYPE_CERES;
		SetASN1Type(ASN1TYPE_CERES);

		pPublicKeyObject = new CPKCS11PublicKeyObject();

		// Atributos comunes de todos los objetos P11
		pPublicKeyObject->SetAttribute( CKA_PRIVATE,
										CUtil::GetBit( asn1PUKDFCeres->commonObjectAttributes.flags, CommonObjectFlags_private ) );
		pPublicKeyObject->SetAttribute( CKA_MODIFIABLE,
										CUtil::GetBit( asn1PUKDFCeres->commonObjectAttributes.flags, CommonObjectFlags_modifiable ) );
		if(asn1PUKDFCeres->commonObjectAttributes.label)
		{
			pPublicKeyObject->SetAttribute( CKA_LABEL,
											asn1PUKDFCeres->commonObjectAttributes.label->choice.tipot61string.buf,
											asn1PUKDFCeres->commonObjectAttributes.label->choice.tipot61string.size );
		}

		// Atributos comunes de claves
		pPublicKeyObject->SetAttribute( CKA_KEY_TYPE, (ulong)CKK_RSA);
		pPublicKeyObject->SetAttribute( CKA_ID,
										asn1PUKDFCeres->classAttributes.iD.buf,
										asn1PUKDFCeres->classAttributes.iD.size);
		pPublicKeyObject->SetAttribute( CKA_LOCAL,
										CUtil::GetBit( asn1PUKDFCeres->classAttributes.accessFlags, KeyAccessFlags_local ) );
		pPublicKeyObject->SetAttribute( CKA_DERIVE,
										CUtil::GetBit( &asn1PUKDFCeres->classAttributes.usage, KeyUsageFlags_derive ) );
		
		if(asn1PUKDFCeres->classAttributes.startDate)
		{
			pPublicKeyObject->SetAttribute( CKA_START_DATE,
											 asn1PUKDFCeres->classAttributes.startDate->buf,
											 asn1PUKDFCeres->classAttributes.startDate->size );
		}

		if(asn1PUKDFCeres->classAttributes.endDate)
		{
			pPublicKeyObject->SetAttribute( CKA_END_DATE,
											 asn1PUKDFCeres->classAttributes.endDate->buf,
											 asn1PUKDFCeres->classAttributes.endDate->size );
		}

		// Atributos de claves públicas
		if(asn1PUKDFCeres->subClassAttributes)
		{
			pPublicKeyObject->SetAttribute( CKA_SUBJECT,
											asn1PUKDFCeres->subClassAttributes->buf,
											asn1PUKDFCeres->subClassAttributes->size );
		}
		pPublicKeyObject->SetAttribute( CKA_ENCRYPT,
										CUtil::GetBit( &asn1PUKDFCeres->classAttributes.usage, KeyUsageFlags_encrypt ) );
		pPublicKeyObject->SetAttribute( CKA_VERIFY,
										CUtil::GetBit( &asn1PUKDFCeres->classAttributes.usage, KeyUsageFlags_verify ) );
		pPublicKeyObject->SetAttribute( CKA_VERIFY_RECOVER,
										CUtil::GetBit( &asn1PUKDFCeres->classAttributes.usage, KeyUsageFlags_verifyRecover ) );
		pPublicKeyObject->SetAttribute( CKA_WRAP,
										CUtil::GetBit( &asn1PUKDFCeres->classAttributes.usage, KeyUsageFlags_wrap ) );

		// Resto de atributos para inicialización de flags PKCS#15
		pPublicKeyObject->SetAttribute( CKA_DECRYPT,
										CUtil::GetBit( &asn1PUKDFCeres->classAttributes.usage, KeyUsageFlags_decrypt ) );
		pPublicKeyObject->SetAttribute( CKA_SIGN,
										CUtil::GetBit( &asn1PUKDFCeres->classAttributes.usage, KeyUsageFlags_sign ) );
		pPublicKeyObject->SetAttribute( CKA_SIGN_RECOVER,
										CUtil::GetBit( &asn1PUKDFCeres->classAttributes.usage, KeyUsageFlags_signRecover ) );
		pPublicKeyObject->SetAttribute( CKA_UNWRAP,
										CUtil::GetBit( &asn1PUKDFCeres->classAttributes.usage, KeyUsageFlags_unwrap ) );
		// Nos creamos un atributo propio para mantener el NO REPUDIO del KeyUsage
		pPublicKeyObject->SetAttribute( CKA_VD_NONREPUDIATION,
			CUtil::GetBit( &asn1PUKDFCeres->classAttributes.usage,KeyUsageFlags_nonRepudiation) );

		pPublicKeyObject->SetAttribute( CKA_SENSITIVE,
										CUtil::GetBit( asn1PUKDFCeres->classAttributes.accessFlags, KeyAccessFlags_sensitive ) );
		pPublicKeyObject->SetAttribute( CKA_EXTRACTABLE,
										CUtil::GetBit( asn1PUKDFCeres->classAttributes.accessFlags, KeyAccessFlags_extractable ) );
		pPublicKeyObject->SetAttribute( CKA_ALWAYS_SENSITIVE,
										CUtil::GetBit( asn1PUKDFCeres->classAttributes.accessFlags, KeyAccessFlags_alwaysSensitive ) );
		pPublicKeyObject->SetAttribute( CKA_NEVER_EXTRACTABLE,
										CUtil::GetBit( asn1PUKDFCeres->classAttributes.accessFlags, KeyAccessFlags_neverExtractable ) );

		pPublicKeyObject->SetAttribute( CKA_MODULUS_BITS,
										(ulong)CUtil::GetInt32( &asn1PUKDFCeres->typeAttributes.modulusLength ) );

		// Parámetros del PKCS#15
		pPublicKeyObject->SetKeyReference( CUtil::GetInt32( &asn1PUKDFCeres->classAttributes.keyReference ) );
		pPublicKeyObject->SetKeyLen((ulong)CUtil::GetInt32( &asn1PUKDFCeres->typeAttributes.modulusLength) );

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

		pPublicKeyObject->SetValuePath( asn1PUKDFCeres->typeAttributes.value.path.buf,
										asn1PUKDFCeres->typeAttributes.value.path.size,
										CUtil::GetInt32( asn1PUKDFCeres->typeAttributes.value.index ),
										CUtil::GetInt32( (INTEGER_t *)asn1PUKDFCeres->typeAttributes.value.length ) );

		m_P11Objects.push_back( pPublicKeyObject );

		nRet = 1;
	}

	if( asn1PUKDFCeres )
	{
		asn_DEF_PublicKeyObjectCERES.free_struct(&asn_DEF_PublicKeyObjectCERES, asn1PUKDFCeres, 0);
		asn1PUKDFCeres = NULL;
	}

	return nRet;

}
