#include "Comm_DNIe.h"

#include "modes.h"		// Para modos de cifrado CBC EBC ...
#include "des.h"		// Para el cálculo del MAC

#include "DNIe-channelParams.h"

using namespace CryptoPP;

CComm_DNIe::CComm_DNIe( CSlot & slot ) : CCommunicator( slot )
{
	m_secureChannel = false;

	m_macLen = 4;

	// Tipo de tarjeta CWA:
	// - FNMT
	// - DNIe
	// - DNIe 3.0
	m_DniType = slot.m_DniType;

	//
	// Prueba de establecimiento de canal, y envío de comandos
	//
/*
	setChannel();

	byteBuffer	answer;
	sendAPDU( (byte *)"\x90\xb8\x00\x00\x11", 5, answer );

	byteBuffer	pin( (byte *)"pindeusuario", 12 );

	byteBuffer cmd( (byte *)"\x00\x20\x00\x00", 4 );
	cmd.push_back( pin.size() );
	cmd += pin;

	sendAPDU( cmd, answer );
*/
};

CComm_DNIe::~CComm_DNIe()
{
	m_secureChannel = false;
	m_kenc.zeroClear();
	m_kmac.zeroClear();
	m_ssc.zeroClear();
	#if defined _CFG_CACHE_PIN
		m_bbRest.zeroClear();
	#endif
	
}

void CComm_DNIe::setChannel( bool isPinChannel )
{
	byteBuffer		apdu;				// Comando a enviar a la tarjeta
	byteBuffer		answer;				// Respuesta de la tarjeta
	sChannelData	channelData;		// Parámetros de establecimiento de canal

	byteBuffer		plainData;			// Datos en claro
	byteBuffer		cryptedData;		// Datos cifrados

	byteBuffer		C_CAicc_AUT;		// Certificado de la CA de componente
	RSA_PublicKey	PK_CAicc_AUT;		// Clave pública de la CA de componente (extraida
										// del certificado de CA de componente)

	byteBuffer		C_ICC_AUT;			// Certificado del componente
	RSA_PublicKey	PK_ICC_AUT;			// Clave pública de la tarjeta (extraida del
										// certificado de componente) PK.ICC.AUT

	byteBuffer		sn_ICC;				// Número de serie de la tarjeta


	loadChannelData( channelData, isPinChannel );

	try
	{
		
		/*//
		// No debe estar el canal establecido previamente
		//
		if( m_secureChannel )
			throw Pkcs11Exception( CKR_GENERAL_ERROR );*/

		//
		// Seleccionamos el Master.File
		//
		SelectFileByName( MF_NAME );

		//
		// Seleccionamos y leemos el certificado de la CA de componente (C.CAicc.AUT) (8.4.1.7)
		//
		SelectFileById(0x6020);
		readEF_sequence( 0, C_CAicc_AUT, 0 );

		//
		// Seleccionamos y leemos el certificado de componente (C.ICC.AUT) (8.4.1.8)
		//
		SelectFileById(0x601F);
		readEF_sequence( 0, C_ICC_AUT , 0 );

		//
		// Pedimos el número de serie, y añadimos un 0x00 inicial
		//
		sendAPDU( (byte *)"\x90\xb8\x00\x00\x07", 5, sn_ICC );
		sn_ICC.insert( sn_ICC.begin(), 0 );

		//
		// Seleccionamos la clave publica de la autoridad certificadora raíz (PK.RCA.AUT), con
		// Manage Security Environment (MSE) - Set DST for verification (8.4.1.2)
		//
		apdu.assign( (byte *)"\x00\x22\x81\xb6", 4 );		// Preparamos la cabecera del comando ...
		apdu.push_back((byte)channelData.PK_RCA_AUT_keyRef.size());	// añadimos longitud de los datos ...
		apdu += channelData.PK_RCA_AUT_keyRef;						// añadimos los datos ...
		sendAPDU( apdu, answer );							// y enviamos el comando

		//
		// Enviamos el certificado C_CV.CA.CS_AUT para su verificación, con
		// Perform security operation (PSO) - Verify Certificate (8.4.1.3)
		//
		apdu.assign( (byte *)"\x00\x2a\x00\xae", 4 );		// Preparamos la cabecera del comando ...
		apdu.append((byte)channelData.C_CV_CA_CS_AUT.size());			// añadimos longitud de los datos ...
		apdu += channelData.C_CV_CA_CS_AUT;							// añadimos los datos ...
		sendAPDU( apdu, answer );							// y enviamos el comando

		//
		// Seleccionamos la clave publica de la ca (PK.CA.CS_AUT) recien cargada con
		// Manage Security Environment (MSE) - Set DST for verification (8.4.1.4)
		//
		apdu.assign( (byte *)"\x00\x22\x81\xb6", 4 );
		apdu.append((byte)channelData.PK_CA_CS_AUT_keyRef.size());
		apdu += channelData.PK_CA_CS_AUT_keyRef;
		sendAPDU( apdu, answer );

		//
		// Enviamos el certificado C_CV.IFD.AUT para su verificación, con
		// Perform security operation - Verify Certificate (8.4.1.5)
		//
		apdu.assign( (byte *)"\x00\x2a\x00\xae", 4 );
		apdu.append((byte)channelData.C_CV_IFD_AUT.size());
		apdu += channelData.C_CV_IFD_AUT;
		sendAPDU( apdu, answer );

		// 13-06-2012: este punto se ha realizado anteriormente para no romper la secuencia de est. canal.
		// Leemos el certificado de la CA de componente (C.CAicc.AUT) con selección por SFI (8.4.1.7)
		//
		//readEF_sequence( /*0x6020*/ 0, C_CAicc_AUT, 0x8000 );

		//
		// Verificamos el certificado de la CA de componente, y obtenemos su
		// clave pública. Si falla la verificación, lanza una excepción.
		//
		CUtil::verify_X509_cert( C_CAicc_AUT, channelData.PK_RCAicc, PK_CAicc_AUT );

		// 13-06-2012: este punto se ha realizado anteriormente para no romper la secuencia de est. canal.
		// Leemos el certificado de componente (C.ICC.AUT) con selección SFI (8.4.1.8)
		//
		//readEF_sequence( /*0x601f*/ 0, C_ICC_AUT , 0x9f00 );

		//
		// Verificamos el certificado de la CA de componente, y obtenemos
		// la clave pública de tarjeta (ICC)
		//
		CUtil::verify_X509_cert( C_ICC_AUT, PK_CAicc_AUT, PK_ICC_AUT);

		//
		// Seleccionamos la clave publica de ifd (PK.IFD.AUT), y la
		// privada de icc (SK.ICC.AUT) con Manage Security Environment (MSE)
		//  - Set DST for internal and external authentication (8.4.1.9)
		//
		apdu.assign( (byte *)"\x00\x22\xC1\xA4", 4 );
		apdu.append((byte)(channelData.PK_IFD_AUT_keyRef.size()+channelData.SK_ICC_AUT_keyRef.size()));
		apdu += channelData.PK_IFD_AUT_keyRef;
		apdu += channelData.SK_ICC_AUT_keyRef;
		sendAPDU( apdu, answer );

		//
		// Enviamos el comando - Internal Authentication (8.4.1.10)
		// Los datos de entrada son:
		//    C = RND.IFD || SN.IFD
		//
		byteBuffer rnd_IFD(8);
		CUtil::GenerateRandomBlock( &rnd_IFD[0], rnd_IFD.size() );

		apdu.assign( (byte *)"\x00\x88\x00\x00\x10", 5 );
		apdu += rnd_IFD;
		apdu += channelData.SN_IFD;

		sendAPDU( apdu, answer, 0x6100 );

		//
		// Leemos la respuesta del comando de Autenticación Interna. Debe ser
		//    E[PK.IFD.AUT](SIGMIN)
		//    SIGMIN = min(SIG, N.ICC - SIG);
		//    SIG = DS1[SK.ICC.AUT](‘6A’ || PRND1 || KICC || h(PRND1 || KICC || RND.IFD || SN.IFD) || ‘BC’)
		//
		// Si habíamos montado anteriormente canal CWA14890 (canal Pin), ya tendremos disponible la respuesta
		if(!m_secureChannel)
			getResponse( cryptedData );
		else
			cryptedData = answer;

		//
		// Desciframos la respuesta con la clave privada de IFD ...
		//
		CUtil::RSA_private( channelData.SK_IFD_AUT, cryptedData, cryptedData );

		//
		// Lo que tenemos ahora es SIGMIN = min(SIG, N.ICC-SIG), con
		//    SIG = DS1[SK.ICC.AUT](‘6A’ || PRND1 || KICC || h(PRND1 || KICC || C) || ‘BC’)
		// Hay que probar las dos posibilidad (SIG, o N.ICC-SIG).
		// Primero asumimos SIG, desciframos con PK_ICC_AUT ...
		//
		CUtil::RSA_public( PK_ICC_AUT, cryptedData, plainData );

		//
		// Calculamos el hash, y comprobamos si coincide ..
		//
		byteBuffer	hashIn = plainData.substr(1,plainData.size()-22) + rnd_IFD + channelData.SN_IFD;
		byteBuffer	hash = CUtil::sha1( hashIn );

		if( plainData[0] != 0x6a || plainData[plainData.size()-1] != 0xbc ||
			memcmp(&hash[0],&plainData[plainData.size()-21],20) )
		{
			//
			// Como no es correcto, probamos la otra posibilidad.
			// Ahora asumimos SIGMIN = N.ICC-SIG, por tanto obtenemos
			//    SIG = N.ICC - SIGMIN
			//
			Integer	a;
			a.Decode(&cryptedData[0],cryptedData.size());
			a = PK_ICC_AUT.m_n - a;
			a.Encode(&cryptedData[0],cryptedData.size());

			//
			// ... y desciframos de nuevo con pk_ICC_AUT para obtener SIG
			//
			CUtil::RSA_public( PK_ICC_AUT, cryptedData, plainData );

			//
			// Calculamos el Hash, y lo verificamos.
			// También comprobamos el relleno '6a'...''bc'
			//
			hashIn = plainData.substr(1,plainData.size()-22) + rnd_IFD + channelData.SN_IFD;
			hash = CUtil::sha1( hashIn );

			if( plainData[0] != 0x6a || plainData[plainData.size()-1] != 0xbc ||
				memcmp(&hash[0],&plainData[plainData.size()-21],20) )
			{
				throw Pkcs11Exception( CKR_DATA_INVALID );
			}
		}

		//
		// Extraemos Kicc de la respuesta descifrada
		//
		byteBuffer	Kicc = plainData.substr( plainData.size()-20-1-32, 32 );

		//
		// Pedimos un desafio de 8 bytes con Get Challenge (8.4.1.11)
		//
		byteBuffer	rnd_ICC;
		sendAPDU( (byte *)"\x00\x84\x00\x00\x08", 5, rnd_ICC );

		//
		// Realizamos la Autenticación Externa. External Authentication (8.4.1.12)
		// Los datos que debemos enviar en el comando son:
		//    E[PK.ICC.AUT](SIGMIN)
		//    SIGMIN = min(SIG, N.IFD - SIG)
		//    SIG = DS1[SK.IFD.AUT](’6A’ || PRND || KIFD || h(PRND.|| KIFD || RND.ICC || SN.ICC) || ‘BC’)
		//

		//
		// Generamos Kifd y PRND (aleatorios). El tamaño del relleno (PRND) es el
		// tamaño del mensaje(o de las claves) menos el tamaño del resto de los campos
		//
		byteBuffer	PRND( PK_ICC_AUT.m_n.ByteCount() - 2-20-32 );
		CUtil::GenerateRandomBlock( &PRND[0], PRND.size() );

		byteBuffer	Kifd(32);
		CUtil::GenerateRandomBlock(&Kifd[0],Kifd.size());

		//
		// Calculamos el hash:
		//    h(PRND.|| KIFD || RND.ICC || SN.ICC)
		//
		hashIn = PRND + Kifd + rnd_ICC + sn_ICC;
		hash = CUtil::sha1( hashIn );

		//
		// Construimos el mensaje a cifrar:
		//    ’6A’ || PRND || KIFD || h(PRND.|| KIFD || RND.ICC || SN.ICC) || ‘BC’
		//
		plainData = PRND + Kifd + hash;
		plainData.insert(plainData.begin(),0x6a);
		plainData.push_back(0xbc);

		//
		// Lo ciframos con la clave privada del IFD:
		//    SIG = DS1[SK.IFD.AUT](’6A’ || PRND || KIFD || h(PRND.|| KIFD || RND.ICC || SN.ICC) || ‘BC’)
		//
		CUtil::RSA_private( channelData.SK_IFD_AUT, plainData, cryptedData );

		//
		// Calculamos SIGMIN = min(SIG, N.IFD - SIG)
		//
		cryptedData = CUtil::sigmin( cryptedData, channelData.SK_IFD_AUT.m_n );

		//
		// y lo ciframos con la clave pública de la tarjeta,
		//    E[PK.ICC.AUT](SIGMIN)
		//
		CUtil::RSA_public( PK_ICC_AUT, cryptedData, cryptedData );

//		_ASSERT( cryptedData.size() == 0x80 );

		//
		// Construimos el mensaje de autenticación externa, y lo enviamos
		//
		apdu.assign( (byte *)"\x00\x82\x00\x00", 4 );
		apdu.push_back((byte)cryptedData.size());
		apdu += cryptedData;
		sendAPDU( apdu, answer );

		//
		// Calculamos las claves del canal (8.4.2 y 8.8)
		//
		byteBuffer Kifd_icc(32);

		Kifd_icc = Kicc ^ Kifd;

		byteBuffer	counter_C( (byte *)"\x00\x00\x00\x01", 4 );
		hashIn = Kifd_icc + counter_C;
		m_kenc = CUtil::sha1(hashIn).substr(0,16);

		counter_C[3] = 2;					// counter_C = '00000002'
		hashIn = Kifd_icc + counter_C;
		m_kmac = CUtil::sha1(hashIn).substr(0,16);

		//
		// Calculamos el SSC (9.6)
		//
		m_ssc = rnd_ICC.substr(4,4) + rnd_IFD.substr(4,4);

		//
		// El canal ya está establecido
		//
		m_secureChannel = true;

		// Configuramos el tamaño del MAC
		//m_macLen = channelData.MAC_Len;		
		m_macLen = (m_DniType == 2)? 8:channelData.MAC_Len;
		
		//
		// Destruimos los datos utilizados para establecer el canal
		//
		freeChannelData( channelData );
	}
	catch( Pkcs11Exception & e )
	{
		freeChannelData( channelData );
		if( (e.getErrId() & 0xffff0000) == 0x80100000 )
			throw Pkcs11Exception( CKR_DEVICE_ERROR );
		else
			throw e;
	}

}


void CComm_DNIe::loadChannelData( sChannelData & channelData, bool isPinChannel )
{
	//
	// Datos del canal.
	//

	DNIe_channelParams *	pDNIeParams = NULL;
	asn_dec_rval_t			ret_val;
	const byteBuffer &		params	  = m_slot.getTokenType().getParams();
	const byteBuffer &		paramsPIN = m_slot.getTokenType().getParamsPIN();

	ret_val = ber_decode( NULL,
						 &asn_DEF_DNIe_channelParams,
						 (void**)&pDNIeParams,
						 isPinChannel?(void*)&paramsPIN[0]:(void*)&params[0],
						 isPinChannel?paramsPIN.size():params.size() );

	if(ret_val.code == RC_FAIL)
		throw Pkcs11Exception( CKR_GENERAL_ERROR );

	channelData.PK_RCAicc.m_n = Integer( pDNIeParams->pk_RCAicc.n.buf, pDNIeParams->pk_RCAicc.n.size );
	channelData.PK_RCAicc.m_e = Integer( pDNIeParams->pk_RCAicc.e.buf, pDNIeParams->pk_RCAicc.e.size );

	channelData.PK_RCA_AUT_keyRef = byteBuffer( pDNIeParams->pk_RCA_AUT_keyRef.buf, pDNIeParams->pk_RCA_AUT_keyRef.size );
	channelData.C_CV_CA_CS_AUT = byteBuffer( pDNIeParams->c_CV_CA_CS_AUT.buf, pDNIeParams->c_CV_CA_CS_AUT.size );

	channelData.PK_CA_CS_AUT_keyRef = byteBuffer( pDNIeParams->pk_CA_CS_AUT_keyRef.buf, pDNIeParams->pk_CA_CS_AUT_keyRef.size );
	channelData.C_CV_IFD_AUT = byteBuffer( pDNIeParams->c_CV_IFD_AUT.buf, pDNIeParams->c_CV_IFD_AUT.size );

	channelData.IFD_keyRef = byteBuffer( pDNIeParams->ifd_keyRef.buf, pDNIeParams->ifd_keyRef.size );

	channelData.SN_IFD = byteBuffer( pDNIeParams->sn_IFD.buf, pDNIeParams->sn_IFD.size );

	channelData.PK_IFD_AUT_keyRef = byteBuffer( pDNIeParams->pk_IFD_AUT_keyRef.buf, pDNIeParams->pk_IFD_AUT_keyRef.size );
	channelData.SK_ICC_AUT_keyRef = byteBuffer( pDNIeParams->sk_ICC_AUT_keyRef.buf, pDNIeParams->sk_ICC_AUT_keyRef.size );

	channelData.SK_IFD_AUT.m_n = Integer( pDNIeParams->sk_IFD_AUT.n.buf, pDNIeParams->sk_IFD_AUT.n.size );
	channelData.SK_IFD_AUT.m_d = Integer( pDNIeParams->sk_IFD_AUT.d.buf, pDNIeParams->sk_IFD_AUT.d.size );
	channelData.SK_IFD_AUT.m_e = Integer( pDNIeParams->sk_IFD_AUT.e.buf, pDNIeParams->sk_IFD_AUT.e.size );

	channelData.MAC_Len = pDNIeParams->mac_Len?pDNIeParams->mac_Len->buf[0]:4;

	if( pDNIeParams )
		asn_DEF_DNIe_channelParams.free_struct( &asn_DEF_DNIe_channelParams, pDNIeParams, 0 );

	return;
}

void CComm_DNIe::freeChannelData( sChannelData & channelData )
{
	//
	// Debe sobre-escribir las claves y datos ...
	//
	channelData.PK_RCAicc.m_n.Zero();
	channelData.PK_RCAicc.m_e.Zero();

	channelData.PK_RCA_AUT_keyRef.zeroClear();
	channelData.C_CV_CA_CS_AUT.zeroClear();

	channelData.PK_CA_CS_AUT_keyRef.zeroClear();
	channelData.C_CV_IFD_AUT.zeroClear();

	channelData.IFD_keyRef.zeroClear();

	channelData.SN_IFD.zeroClear();

	channelData.PK_IFD_AUT_keyRef.zeroClear();
	channelData.SK_ICC_AUT_keyRef.zeroClear();

	channelData.SK_IFD_AUT.m_n.Zero();
	channelData.SK_IFD_AUT.m_d.Zero();
	channelData.SK_IFD_AUT.m_e.Zero();
}

void CComm_DNIe::sendAPDU( byteBuffer &cmd, byteBuffer & answer, unsigned short expected_SW /*= 0x9000*/ )
{
	sendAPDU( &cmd[0], cmd.size(), answer, expected_SW );
}

void CComm_DNIe::sendAPDU( byte * pCmd, ulong cmdLen, byteBuffer & answer, unsigned short expected_SW /*= 0x9000 */ )
{
	if( !m_secureChannel )
	{
		sendPlainAPDU( pCmd, cmdLen, answer, expected_SW );
		return;
	}

	try
	{
		//
		// Ciframos mensajes
		//

		byteBuffer	secAPDU( pCmd, cmdLen );
		secChannelEncodeAPDU( secAPDU );

		// Jesús: dejamos log de comando en claro
		DBG_DUMP_DIRECT(( "FNMTP11 transmitted (plain):", pCmd, cmdLen ));

		if( secAPDU[4] == 0 )				// Comando con longitud extendida
			sendPlainAPDUExt( secAPDU, answer, 0 );
		else
			sendPlainAPDU( secAPDU, answer, 0 );

		if( (m_SW & 0xff00) != 0x6100 )
			throw Pkcs11Exception( 0x80100000 | m_SW );

		getResponse( answer );

		DBG_DUMP_DIRECT(( "FNMTP11 received (coded):",  &answer[0], answer.size()));
		secChannelDecodeResponse( answer );
		if(answer.size()>0)
			DBG_DUMP_DIRECT(( "FNMTP11 received (plain):",  &answer[0], answer.size()));
	}
	catch( Pkcs11Exception & e )
	{
		m_secureChannel = false;
		m_kenc.zeroClear();
		m_kmac.zeroClear();
		m_ssc.zeroClear();

		throw e;
	}

	//
	// Comprobamos el SW en función de lo esperado
	//
	if( (expected_SW != 0) && (expected_SW != m_SW) && (m_SW != 0x9000))
		throw Pkcs11Exception( 0x80100000 | m_SW );
}

void CComm_DNIe::sendAPDUExt( byteBuffer & cmdHeader, byteBuffer & cmdData, byteBuffer & answer,unsigned short expected_SW )
{
	if(cmdData.size() < 231)
	{
		byteBuffer cmd (cmdHeader);
		cmd.push_back((byte)cmdData.size());
		cmd += cmdData;

		sendAPDU( &cmd[0], cmd.size(), answer, expected_SW );

		return;
	}

	try
	{
		// Construímos el comando extendido
		byteBuffer cmdExt (cmdHeader);
		cmdExt.push_back(0x00);
		cmdExt.push_back((byte)(cmdData.size()>>8));
		cmdExt.push_back(cmdData.size()&0xFF);
		cmdExt += cmdData;

		// Si tenemos canal, codificamos el APDU
		if( m_secureChannel )
			secChannelEncodeAPDU(cmdExt);

		// Construímos el primer Envelope
		byteBuffer cmdEnvelope(( byte *)"\x90\xC2\x00\x00\xFF", 5 );
		cmdEnvelope += cmdExt.substr(0,250);
		cmdEnvelope[4] = (byte)(cmdEnvelope.size()-5);

		sendPlainAPDU(cmdEnvelope, answer);

		// Construímos el segundo Envelope
		cmdEnvelope.assign( (byte *)"\x90\xC2\x00\x00\xFF", 5 );
		cmdEnvelope += cmdExt.substr(250,250);
		cmdEnvelope[4] = (byte)(cmdEnvelope.size()-5);

		sendPlainAPDU(cmdEnvelope, answer, 0);

		if( (m_SW & 0xff00) == 0x6100 )
			getResponse( answer );
		else if( m_SW != 0x9000 )
			throw Pkcs11Exception( 0x80100000 | m_SW );

		// Si tenemos canal, decodificamos la respuesta
		if( m_secureChannel )
			secChannelDecodeResponse( answer );

	}
	catch( Pkcs11Exception & e )
	{
		m_secureChannel = false;
		m_kenc.zeroClear();
		m_kmac.zeroClear();
		m_ssc.zeroClear();

		throw e;
	}

	//
	// Comprobamos el SW en función de lo esperado
	//
	if( (expected_SW != 0) && (expected_SW != m_SW) )
		throw Pkcs11Exception( 0x80100000 | m_SW );

}


//
// Construcción de APDU securizado
//
void CComm_DNIe::secChannelEncodeAPDU( byteBuffer & apdu )
{
	byteBuffer data = apdu.substr(5,apdu.size()-5);
	byteBuffer cc;

	//
	// Comprobamos si tenemos datos en el APDU
	//
	if( data.size() )
	{
		//
		// El tamaño debe coincidir con Lc (en byte 4 del APDU)
		//
		if( apdu[4] != data.size() )
		{
			if( (apdu[4] != 0x00)		||
				(data.size() <= 2)		||
				((size_t)((data[0]<<8) + data[1]) != data.size() - 2) )
					throw Pkcs11Exception( CKR_DATA_INVALID );

			data.erase(data.begin(),data.begin()+2);
		}

		//
		// Añadimos el relleno 7816 ( 80 00 ... ) hasta tamaño múltiplo de 8 bytes
		//
		CUtil::addPadding_7816( data );

		//
		// Ciframos los datos con Kenc
		//
		CUtil::DES_EDE2_cipher( data, m_kenc );

		//
		// Construimos el TLV de datos, añadiendo primero el 'Padding-content indicator byte'
		//
		data.insert(data.begin(),1);
		CUtil::buildTLV( 0x87, data );
	}
	else if( apdu[4] )
	{
		//
		// Si no tenemos datos, byte 4 es Le. Lo codificamos en el TLV correspondiente
		//
		data.push_back(apdu[4]);
		CUtil::buildTLV( 0x97, data );
	}

	//
	// Comenzamos preparación de los datos para el cálculo del CC.
	// Primero los 4 bytes CLA INS P1 P2, con relleno 7816 (80 00 00 00)
	//
	apdu[0] |= 0x0c;
	byteBuffer mac_input = apdu.substr(0,4);
	CUtil::addPadding_7816( mac_input );

	//
	// Añadimos los datos, y/o TLV de datos esperados, y completamos
	// de nuevo con relleno 7816, hasta múltiplo de 8 bytes.
	//
	if( data.size() )
	{
		mac_input += data;
		CUtil::addPadding_7816( mac_input );
	}

	//
	// Calculamos el CC, y construimos el TLV
	//
	computeMAC( mac_input, cc );
	CUtil::buildTLV( 0x8e, cc );

	//
	// Construimos el mensaje final, juntando todo
	//
	if(data.size()+cc.size() <256)
	{
		apdu.resize(5);
		apdu[4] = (byte)(data.size()+cc.size());
	}
	else
	{
		// Construímos APDU extendido con longitud de 3 bytes
		apdu.resize(7);
		apdu[4] = 0;
		apdu[5] = (byte)((data.size()+cc.size())>>8);
		apdu[6] = (data.size()+cc.size())&0xFF;
	}

	apdu += data + cc;
}

//
// Decodificación de respuesta securizada
//
void CComm_DNIe::secChannelDecodeResponse( byteBuffer & answer )
{
	long		tag;
	long		offset = 0;
	byteBuffer	data;
	long		dataLen;
	byteBuffer	cc;
	unsigned short	sw;

	offset += CUtil::getTLV( &answer[offset], &tag, &dataLen );
	if( tag == 0x87 )
	{
		//
		// Tenemos campo de datos, comprobamos su formato, y
		// eliminamos el 'Padding-content indicator byte'
		if( (dataLen % 8) != 1 || answer[offset] != 1 )
			throw Pkcs11Exception( CKR_DATA_INVALID );

		data = answer.substr( offset+1, dataLen-1 );

		//
		// Leemos los datos del siguiente TLV
		//
		offset += dataLen;
		offset += CUtil::getTLV( &answer[offset], &tag, &dataLen );
	}

	//
	// Debe existir el TLV con el SW, y debe ser de 2 bytes. Lo leemos.
	//
	if( tag != 0x99 )
		throw Pkcs11Exception( CKR_DATA_INVALID );

	if( dataLen != 2 )
		throw Pkcs11Exception( CKR_DATA_INVALID );

	sw = (answer[offset]<<8) + answer[offset+1];

	//
	// Todo el mensaje hasta este punto, es la entrada para el cálculo de MAC
	//
	offset += dataLen;
	byteBuffer mac_input = answer.substr( 0, offset );
	CUtil::addPadding_7816( mac_input );

	//
	// Leemos el siguiente TLV, que debe ser el del CC (de tamaño m_macLen)
	//
	offset += CUtil::getTLV( &answer[offset], &tag, &dataLen );

	if( tag != 0x8e )
		throw Pkcs11Exception( CKR_DATA_INVALID );
	if( dataLen != m_macLen )
		throw Pkcs11Exception( CKR_DATA_INVALID );

	//
	// Calculamos el CC con los datos recibidos, y lo comparamos con el del TLV anterior
	//
	computeMAC( mac_input, cc );

	if( memcmp( &cc[0], &answer[offset], cc.size() ) )
		throw Pkcs11Exception( CKR_DATA_INVALID );

	if( data.size() )
	{
		//
		// Desciframos los datos recibidos ...
		//
		CUtil::DES_EDE2_decipher( data, m_kenc );

		//
		// y eliminamos el relleno 7816.
		//
		CUtil::unPad_7816( data );

		answer = data;
	}
	else
		answer.clear();

	m_SW = sw;

}

void CComm_DNIe::computeMAC( byteBuffer & data, byteBuffer & cc )
{
	//
	// Comprobaciones previas de tamaños
	//
	if( data.size() % 8 )
		throw Pkcs11Exception( CKR_DATA_INVALID );

	if( m_ssc.size() != 8 )
		throw Pkcs11Exception( CKR_DATA_INVALID );

	if( m_kenc.size() != 16 )
		throw Pkcs11Exception( CKR_DATA_INVALID );

	//
	// Incrementamos el contador de secuencia
	//
	Integer	tmp;
	tmp.Decode( &m_ssc[0], m_ssc.size() );
	tmp ++;
	tmp.Encode( &m_ssc[0], m_ssc.size() );

	//
	// Preparamos el cifrado. Ka con los 8 primeros bytes de m_kmac,
	// y Kb con los 8 últimos
	//
	ECB_Mode< DES >::Encryption mac_Ka;
	ECB_Mode< DES >::Decryption mac_Kb;
	mac_Ka.SetKey(&m_kmac[0],8);
	mac_Kb.SetKey(&m_kmac[8],8);

	cc = m_ssc;

	for( size_t offset = 0; offset<data.size(); offset += 8 )
	{
		//
		// Cifrado de CC con Ka
		//
		mac_Ka.ProcessData( &cc[0], &cc[0], 8 );

		//
		// XOR de CC con el siguiente bloque de datos
		//
		for( long idx = 0; idx<8; idx++ )
			cc[idx] ^= data[offset+idx];

	}

	//
	// Cifrado triple DES final (EDE2)
	//
	mac_Ka.ProcessData( &cc[0], &cc[0], 8 );
	mac_Kb.ProcessData( &cc[0], &cc[0], 8 );
	mac_Ka.ProcessData( &cc[0], &cc[0], 8 );

	cc.resize(m_macLen);
}

void CComm_DNIe::VerifyPIN( CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen )
{	
	// Si estamos trabajando sobre DNIe 3.0, hay que montar canal PIN
	if(m_DniType==2)
		setChannel(true);
	else 
		if( !m_secureChannel )
			setChannel();

	CCommunicator::VerifyPIN( pPin, ulPinLen );

	// Si estamos trabajando sobre DNIe 3.0:
	//	- tras canal PIN debjamos montado cana USUARIO
	//	- si está configurado, gestionamos la caché de PIN
	if(m_DniType==2) 
	{
		setChannel();
				
		#if defined _CFG_CACHE_PIN
			// Borramos cualquier vestigio de caché de PIN, ya que vamos a utilizar uno nuevo
			m_bbRest.zeroClear();

			// En el slot ya tenemos leído el TokenInfo así que lo parsearemos para obtener el número de serie de la tarjeta
			CK_TOKEN_INFO_PTR pInfo = new CK_TOKEN_INFO[1];
			this->m_slot.GetTokenInfo(pInfo);

			CK_CHAR mySerial[16];
			memset(mySerial, 0xFF, 16);
			memcpy(mySerial, pInfo->serialNumber, 16);
							
			// A partir del número de serie obtenemos la calves DES con la que la cifraremos/descifraremos
			byteBuffer	cardSerial (mySerial, 16);
			byteBuffer	hashSerial = CUtil::sha1(cardSerial).substr(0,16);
		
			// Ciframos la caché de PIN con la claves DES obtenida a partir del número de serie
			byteBuffer bAux(pPin, 16);
			memset(&bAux[0]+ulPinLen, 0x00, 16-ulPinLen);
			CUtil::DES_EDE2_cipher(bAux, hashSerial);
	
			// Dejamos guardado el PIN cifrado en una caché de sesión
			m_bbRest = bAux;
			bAux.zeroClear();
		#endif
	}
}

#if defined _CFG_CACHE_PIN
	// Método para presentar de nuevo el PIN guardado en caché
	void CComm_DNIe::RestorePIN( )
	{
		// Si no hay almacenado caché de PIN, no podemos restaurarlo
		if(m_bbRest.size()==0)
			return;

		// En el slot ya tenemos leído el TokenInfo así que lo parsearemos para obtener el número de serie de la tarjeta
		CK_TOKEN_INFO_PTR pInfo = new CK_TOKEN_INFO[1];
		this->m_slot.GetTokenInfo(pInfo);

		CK_CHAR mySerial[16];
		memset(mySerial, 0xFF, 16);
		memcpy(mySerial, pInfo->serialNumber, 16);
						
		// A partir del número de serie obtenemos la calves DES con la que la cifraremos/descifraremos
		byteBuffer	cardSerial (mySerial, 16);
		byteBuffer	hashSerial = CUtil::sha1(cardSerial).substr(0,16);
	
		// Desciframos la caché de PIN con la claves DES obtenida a partir del número de serie
		byteBuffer bbAux = m_bbRest;
		CUtil::DES_EDE2_decipher(bbAux, hashSerial);
	
		// Si estamos trabajando sobre DNIe 3.0, hay que montar canal PIN
		if(m_DniType==2)
			setChannel(true);
		else 
			if( !m_secureChannel )
				setChannel();

		try{
			// Presentamos el PIN de la caché, pero si fuese incorrecto, la borraríamos
			CCommunicator::VerifyPIN( &bbAux[0], strlen((char*)&bbAux[0]));
			bbAux.zeroClear();
		}
		catch (Pkcs11Exception e)
		{
			bbAux.zeroClear();

			if ( (e.getErrId() == CKR_PIN_LOCKED)		||
				 (e.getErrId() == CKR_PIN_INCORRECT)	||
				 (e.getErrId() == CKR_USER_NOT_LOGGED_IN) )
			{
				m_bbRest.zeroClear();
			}

			throw e;
		}

		// Si estamos trabajando sobre DNIe 3.0, tras canal PIN debjamos montado canal USUARIO
		if(m_DniType==2) setChannel();
	}
	
	// Método para sobrecargar la firma mediante un mecanismo, usando si es necesario el PIN guardado en caché
	void CComm_DNIe::SignMech ( CMech * pMechanism, byteBuffer & data, byteBuffer & signature )
	{
		bool bRetry = true;

		while(bRetry)
		{
			bRetry = false;

			// Obtenemos el keyReference de la clave utilizada por el mecanismo
			byte keyReference = pMechanism->GetKeyReference();

			// Modificaremos los datos de entrada en caso de que el mecanismo lo requiera
			pMechanism->ConstructData(data);

			// Seleccionamos la clave RSA con MSE
			byteBuffer	cmd((byte *)"\x00\x22\x41\xB6\x04\x84\x02\x01\x01",9);
			byteBuffer answer;

			cmd[8] = keyReference;
			sendAPDU( cmd, answer );

			// Realizamos la firma con PSO
			cmd.assign( (byte *)"\x00\x2A\x9E\x9A",4 );		// Preparamos la cabecera del comando ...
			cmd.push_back((byte)data.size());				// Añadimos longitud de los datos ...
			cmd += data;									// Añadimos los datos ...

			try{
				// Enviamos el comando de firma
				sendAPDU( cmd, signature );						// Enviamos el código extendido ...
			} 
			catch (Pkcs11Exception & e)
			{
				// Si ha ocurrido el error 6982, intentamos presentar pin de caché
				if( ( m_DniType==0x02) && 
					( e.getErrId() == 0x80106982) )	
				{
					this->RestorePIN();
					
					bRetry = true;
				}
				else 
					throw e;
			}
		}
	}
#endif

void CComm_DNIe::ChangePIN( CK_UTF8CHAR_PTR pOldPin, CK_ULONG ulOldLen,
							CK_UTF8CHAR_PTR pNewPin, CK_ULONG ulNewLen,
							byte bCodeId )
{
	if( !m_secureChannel )
		setChannel();

	CCommunicator::ChangePIN( pOldPin, ulOldLen, pNewPin, ulNewLen, bCodeId );
}

void CComm_DNIe::UnblockPIN( CK_UTF8CHAR_PTR pUnblock, CK_ULONG ulUnbLen,
							 CK_UTF8CHAR_PTR pNewPIN, CK_ULONG ulPinLen)
{
	if( !m_secureChannel )
		setChannel();

	CCommunicator::UnblockPIN( pUnblock, ulUnbLen, pNewPIN, ulPinLen );
}


ushort CComm_DNIe::GetPINCounter()
{
	// Si estamos trabajando sobre DNIe 3.0, hay que montar canal PIN
	if(m_DniType==2)
		setChannel(true);
	else 
		if( !m_secureChannel )
			setChannel();

	ushort usPinLen =  CCommunicator::GetPINCounter();

	// Si estamos trabajando sobre DNIe 3.0, tras canal PIN debjamos montado cana USUARIO
	if(m_DniType==2) setChannel();

	return usPinLen;
}


int CComm_DNIe::GetDniType()
{
	// Devolvemos el tipo de DNIe
	return m_DniType;
}
