📄 iso7816_4.c
字号:
/* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support
* ----------------------------------------------------------------------------
* Copyright (c) 2008, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ----------------------------------------------------------------------------
*/
//------------------------------------------------------------------------------
// Headers
//------------------------------------------------------------------------------
#include <board.h>
#include <usart/usart.h>
#include <utility/trace.h>
#include <pio/pio.h>
#include "iso7816_4.h"
#include "iso7816_3.h"
//------------------------------------------------------------------------------
// Definitions
//------------------------------------------------------------------------------
// Case for APDU commands
#define CASE1 1
#define CASE2 2
#define CASE3 3
// Flip flop for send and receive char
#define USART_SEND 0
#define USART_RCV 1
//------------------------------------------------------------------------------
// Internal variables
//------------------------------------------------------------------------------
static unsigned char StateUsartGlobal = USART_RCV;
static Pin st_pinIso7816RstMC;
//-----------------------------------------------------------------------------
// Internal functions
//-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
/// Get a character from ISO7816
/// \param pCharToReceive Pointer for store the received char
/// \return 0: if timeout else status of US_CSR
//------------------------------------------------------------------------------
static unsigned int ISO7816_GetChar( unsigned char *pCharToReceive )
{
unsigned int status;
unsigned int timeout=0;
if( StateUsartGlobal == USART_SEND ) {
while((AT91C_BASE_US0->US_CSR & AT91C_US_TXEMPTY) == 0) {}
AT91C_BASE_US0->US_CR = AT91C_US_RSTSTA | AT91C_US_RSTIT | AT91C_US_RSTNACK;
StateUsartGlobal = USART_RCV;
}
// Wait USART ready for reception
while( ((AT91C_BASE_US0->US_CSR & AT91C_US_RXRDY) == 0) ) {
if(timeout++ >6000) {
trace_LOG(trace_DEBUG, "TimeOut\n\r");
return( 0 );
}
}
trace_LOG(trace_DEBUG, "T: %d\n\r", timeout);
// At least one complete character has been received and US_RHR has not yet been read.
// Get a char
*pCharToReceive = ((AT91C_BASE_US0->US_RHR) & 0xFF);
status = (AT91C_BASE_US0->US_CSR&(AT91C_US_OVRE|AT91C_US_FRAME|
AT91C_US_PARE|AT91C_US_TIMEOUT|AT91C_US_NACK|
(1<<10)));
if (status != 0 ) {
// trace_LOG(trace_DEBUG, "R:0x%X\n\r", status);
trace_LOG(trace_DEBUG, "R:0x%X\n\r", AT91C_BASE_US0->US_CSR);
trace_LOG(trace_DEBUG, "Nb:0x%X\n\r", AT91C_BASE_US0->US_NER );
AT91C_BASE_US0->US_CR = AT91C_US_RSTSTA;
}
// Return status
return( status );
}
//------------------------------------------------------------------------------
/// Send a char to ISO7816
/// \param CharToSend char to be send
/// \return status of US_CSR
//------------------------------------------------------------------------------
static unsigned int ISO7816_SendChar( unsigned char CharToSend )
{
unsigned int status;
if( StateUsartGlobal == USART_RCV ) {
AT91C_BASE_US0->US_CR = AT91C_US_RSTSTA | AT91C_US_RSTIT | AT91C_US_RSTNACK;
StateUsartGlobal = USART_SEND;
}
// Wait USART ready for transmit
while((AT91C_BASE_US0->US_CSR & AT91C_US_TXRDY) == 0) {}
// There is no character in the US_THR
// Transmit a char
AT91C_BASE_US0->US_THR = CharToSend;
status = (AT91C_BASE_US0->US_CSR&(AT91C_US_OVRE|AT91C_US_FRAME|
AT91C_US_PARE|AT91C_US_TIMEOUT|AT91C_US_NACK|
(1<<10)));
if (status != 0 ) {
trace_LOG(trace_DEBUG, "E:0x%X\n\r", AT91C_BASE_US0->US_CSR);
trace_LOG(trace_DEBUG, "Nb:0x%X\n\r", AT91C_BASE_US0->US_NER );
AT91C_BASE_US0->US_CR = AT91C_US_RSTSTA;
}
// Return status
return( status );
}
//------------------------------------------------------------------------------
/// Iso 7816 ICC power on
//------------------------------------------------------------------------------
static void ISO7816_IccPowerOn( void )
{
// Set RESET Master Card
PIO_Set(&st_pinIso7816RstMC);
}
//-----------------------------------------------------------------------------
// Exported functions
//-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
/// Iso 7816 ICC power off
//------------------------------------------------------------------------------
void ISO7816_IccPowerOff( void )
{
// Clear RESET Master Card
PIO_Clear(&st_pinIso7816RstMC);
}
//------------------------------------------------------------------------------
/// Transfert Block TPDU T=0
/// \param pAPDU APDU buffer
/// \param pMessage Message buffer
/// \param wLength Block length
/// \return Message index
//------------------------------------------------------------------------------
unsigned short ISO7816_XfrBlockTPDU_T0(const unsigned char *pAPDU,
unsigned char *pMessage,
unsigned short wLength )
{
unsigned short NeNc;
unsigned short indexApdu = 4;
unsigned short indexMessage = 0;
unsigned char SW1 = 0;
unsigned char procByte;
unsigned char cmdCase;
trace_LOG(trace_DEBUG, "pAPDU[0]=0x%X\n\r",pAPDU[0]);
trace_LOG(trace_DEBUG, "pAPDU[1]=0x%X\n\r",pAPDU[1]);
trace_LOG(trace_DEBUG, "pAPDU[2]=0x%X\n\r",pAPDU[2]);
trace_LOG(trace_DEBUG, "pAPDU[3]=0x%X\n\r",pAPDU[3]);
trace_LOG(trace_DEBUG, "pAPDU[4]=0x%X\n\r",pAPDU[4]);
trace_LOG(trace_DEBUG, "pAPDU[5]=0x%X\n\r",pAPDU[5]);
trace_LOG(trace_DEBUG, "wlength=%d\n\r",wLength);
ISO7816_SendChar( pAPDU[0] ); // CLA
ISO7816_SendChar( pAPDU[1] ); // INS
ISO7816_SendChar( pAPDU[2] ); // P1
ISO7816_SendChar( pAPDU[3] ); // P2
ISO7816_SendChar( pAPDU[4] ); // P3
// Handle the four structures of command APDU
indexApdu = 4;
if( wLength == 4 ) {
cmdCase = CASE1;
NeNc = 0;
}
else if( wLength == 5) {
cmdCase = CASE2;
NeNc = pAPDU[4]; // C5
if (NeNc == 0) {
NeNc = 256;
}
}
else if( wLength == 6) {
NeNc = pAPDU[4]; // C5
cmdCase = CASE3;
}
else if( wLength == 7) {
NeNc = pAPDU[4]; // C5
if( NeNc == 0 ) {
cmdCase = CASE2;
NeNc = (pAPDU[5]<<8)+pAPDU[6];
}
else {
cmdCase = CASE3;
}
}
else {
NeNc = pAPDU[4]; // C5
if( NeNc == 0 ) {
cmdCase = CASE3;
NeNc = (pAPDU[5]<<8)+pAPDU[6];
}
else {
cmdCase = CASE3;
}
}
trace_LOG(trace_DEBUG, "CASE=0x%X NeNc=0x%X\n\r", cmdCase, NeNc);
// Handle Procedure Bytes
do {
ISO7816_GetChar(&procByte);
// Handle NULL
if ( procByte == 0x60 ) {
trace_LOG(trace_DEBUG, "INS\n\r");
continue;
}
// Handle SW1
else if ( ((procByte & 0xF0) ==0x60) || ((procByte & 0xF0) ==0x90) ) {
trace_LOG(trace_DEBUG, "SW1\n\r");
SW1 = 1;
}
// Handle INS
else if ( pAPDU[1] == procByte) {
trace_LOG(trace_DEBUG, "HdlINS\n\r");
if (cmdCase == CASE2) {
// receive data from card
do {
ISO7816_GetChar(&pMessage[indexMessage++]);
} while( 0 != --NeNc );
}
else {
// Send data
do {
ISO7816_SendChar(pAPDU[indexApdu++]);
} while( 0 != --NeNc );
}
}
// Handle INS ^ 0xff
else if ( pAPDU[1] == (procByte ^ 0xff)) {
trace_LOG(trace_DEBUG, "HdlINS+\n\r");
if (cmdCase == CASE2) {
// receive data from card
ISO7816_GetChar(&pMessage[indexMessage++]);
}
else {
ISO7816_SendChar(pAPDU[indexApdu++]);
}
NeNc--;
}
else {
// ??
trace_LOG(trace_DEBUG, "procByte=0x%X\n\r", procByte);
break;
}
} while (NeNc != 0);
// Status Bytes
if (SW1 == 0) {
ISO7816_GetChar(&pMessage[indexMessage++]); // SW1
}
else {
pMessage[indexMessage++] = procByte;
}
ISO7816_GetChar(&pMessage[indexMessage++]); // SW2
return( indexMessage );
}
//------------------------------------------------------------------------------
/// Escape ISO7816
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -