From 192aa9abd7b91697da34d23a3c6babe53d6fcf0f Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sun, 8 Apr 2018 10:51:19 +0200 Subject: [PATCH] CHG: renamed iso7816 files ADD: smartcard functionality (big thanks to Chris Nocker!) --- armsrc/Makefile | 6 +- armsrc/appmain.c | 14 +- armsrc/iso7816.c | 148 ---------- armsrc/iso7816.h | 20 -- armsrc/smartcard.c | 702 +++++++++++++++++++++++++++++++++++++++++++++ armsrc/smartcard.h | 17 ++ 6 files changed, 735 insertions(+), 172 deletions(-) delete mode 100644 armsrc/iso7816.c delete mode 100644 armsrc/iso7816.h create mode 100644 armsrc/smartcard.c create mode 100644 armsrc/smartcard.h diff --git a/armsrc/Makefile b/armsrc/Makefile index 3f3262931..a640509f4 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -23,7 +23,7 @@ APP_CFLAGS = -DWITH_CRC \ -DWITH_ICLASS \ -DWITH_FELICA \ -DWITH_FLASH \ - -DWITH_ISO7816 \ + -DWITH_SMARTCARD \ -DWITH_HFSNOOP \ -DWITH_LF_SAMYRUN \ -fno-strict-aliasing -ffunction-sections -fdata-sections @@ -55,7 +55,7 @@ SRC_CRC = crc.c crc16.c crc32.c SRC_ICLASS = iclass.c optimized_cipher.c SRC_LEGIC = legicrf.c legic_prng.c SRC_FLASH = flashmem.c -SRC_ISO7816 = iso7816.c +SRC_SMARTCARD = smartcard.c SRC_BEE = bee.c #the FPGA bitstream files. Note: order matters! @@ -81,7 +81,7 @@ THUMBSRC = start.c \ $(SRC_ZLIB) \ $(SRC_LEGIC) \ $(SRC_FLASH) \ - $(SRC_ISO7816) \ + $(SRC_SMARTCARD) \ appmain.c \ printf.c \ util.c \ diff --git a/armsrc/appmain.c b/armsrc/appmain.c index f32544ed2..cd1b72313 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -26,6 +26,11 @@ #include "LCD.h" #endif +#ifdef WITH_SMARTCARD +#include "smartcard.h" +#endif + + //============================================================================= // A buffer where we can queue things up to be sent through the FPGA, for // any purpose (fake tag, as reader, whatever). We go MSB first, since that @@ -364,7 +369,7 @@ void SendStatus(void) { BigBuf_print_status(); Fpga_print_status(); Flashmem_print_status(); - //Iso7816_print_status(); + SmartCard_print_status(); printConfig(); //LF Sampling config printUSBSpeed(); Dbprintf("Various"); @@ -1203,6 +1208,10 @@ void __attribute__((noreturn)) AppMain(void) { LCDInit(); #endif +#ifdef WITH_SMARTCARD + SmartCard_init(); +#endif + byte_t rx[sizeof(UsbCommand)]; for(;;) { @@ -1212,6 +1221,9 @@ void __attribute__((noreturn)) AppMain(void) { if ( cmd_receive( (UsbCommand*)rx ) ) UsbPacketReceived(rx, sizeof(UsbCommand) ); +#ifdef WITH_SMARTCARD + SMART_CARD_ServiceSmartCard(); +#endif // Press button for one second to enter a possible standalone mode if (BUTTON_HELD(1000) > 0) { diff --git a/armsrc/iso7816.c b/armsrc/iso7816.c deleted file mode 100644 index 605733385..000000000 --- a/armsrc/iso7816.c +++ /dev/null @@ -1,148 +0,0 @@ -#include "iso7816.h" - -/* here: use NCPS2 @ PA10: */ -#define SPI_CSR_NUM 2 // Chip Select register[] 0,1,2,3 (at91samv512 has 4) - -/* PCS_0 for NPCS0, PCS_1 for NPCS1 ... */ -#define PCS_0 ((0<<0)|(1<<1)|(1<<2)|(1<<3)) // 0xE - 1110 -#define PCS_1 ((1<<0)|(0<<1)|(1<<2)|(1<<3)) // 0xD - 1101 -#define PCS_2 ((1<<0)|(1<<1)|(0<<2)|(1<<3)) // 0xB - 1011 -#define PCS_3 ((1<<0)|(1<<1)|(1<<2)|(0<<3)) // 0x7 - 0111 - -// TODO -#if (SPI_CSR_NUM == 0) -#define SPI_MR_PCS PCS_0 -#elif (SPI_CSR_NUM == 1) -#define SPI_MR_PCS PCS_1 -#elif (SPI_CSR_NUM == 2) -#define SPI_MR_PCS PCS_2 -#elif (SPI_CSR_NUM == 3) -#define SPI_MR_PCS PCS_3 -#else -#error "SPI_CSR_NUM invalid" -// not realy - when using an external address decoder... -// but this code takes over the complete SPI-interace anyway -#endif - - -void ISO7816_setup(void) { - // PA1 -> SIM RST - // PA5 -> SIM I/O - // PA7 -> SIM CLK - - // Disable PIO control of the following pins, allows use by the SPI peripheral - AT91C_BASE_PIOA->PIO_PDR = GPIO_NCS0 | GPIO_MISO | GPIO_MOSI | GPIO_SPCK | GPIO_NCS2; - - // Pull-up Enable - AT91C_BASE_PIOA->PIO_PPUER = GPIO_NCS0 | GPIO_MISO | GPIO_MOSI | GPIO_SPCK | GPIO_NCS2; - - // Peripheral A - AT91C_BASE_PIOA->PIO_ASR = GPIO_NCS0 | GPIO_MISO | GPIO_MOSI | GPIO_SPCK; - - // Peripheral B - AT91C_BASE_PIOA->PIO_BSR |= GPIO_NCS2; - - //enable the SPI Peripheral clock - AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_SPI); - - // Enable SPI - AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIEN; - - // NPCS2 Mode 0 - AT91C_BASE_SPI->SPI_MR = - ( 0 << 24) | // Delay between chip selects (take default: 6 MCK periods) - (0xB << 16) | // Peripheral Chip Select (selects SPI_NCS2 or PA10) - ( 0 << 7) | // Local Loopback Disabled - ( 1 << 4) | // Mode Fault Detection disabled - ( 0 << 2) | // Chip selects connected directly to peripheral - ( 0 << 1) | // Fixed Peripheral Select - ( 1 << 0); // Master Mode - - // 8 bit - AT91C_BASE_SPI->SPI_CSR[2] = - ( 0 << 24) | // Delay between Consecutive Transfers (32 MCK periods) - ( 0 << 16) | // Delay Before SPCK (1 MCK period) - ( 6 << 8) | // Serial Clock Baud Rate (baudrate = MCK/6 = 24Mhz/6 = 4M baud - ( 0 << 4) | // Bits per Transfer (8 bits) - ( 1 << 3) | // Chip Select inactive after transfer - ( 1 << 1) | // Clock Phase data captured on leading edge, changes on following edge - ( 0 << 0); // Clock Polarity inactive state is logic 0 - - // read first, empty buffer - if (AT91C_BASE_SPI->SPI_RDR == 0) {}; -} - -void ISO7816_stop(void) { - //* Reset all the Chip Select register - AT91C_BASE_SPI->SPI_CSR[0] = 0; - AT91C_BASE_SPI->SPI_CSR[1] = 0; - AT91C_BASE_SPI->SPI_CSR[2] = 0; - AT91C_BASE_SPI->SPI_CSR[3] = 0; - - // Reset the SPI mode - AT91C_BASE_SPI->SPI_MR = 0; - - // Disable all interrupts - AT91C_BASE_SPI->SPI_IDR = 0xFFFFFFFF; - - // SPI disable - AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIDIS; - - if ( MF_DBGLEVEL > 3 ) Dbprintf("ISO7816 Stop"); - - StopTicks(); -} - -// send one byte over SPI -uint16_t ISO7816_sendbyte(uint32_t data) { - uint16_t incoming = 0; - - WDT_HIT(); - - // wait until SPI is ready for transfer - while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0) {}; - - // send the data - AT91C_BASE_SPI->SPI_TDR = data; - - // wait recive transfer is complete - while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_RDRF) == 0) - WDT_HIT(); - - // reading incoming data - incoming = ((AT91C_BASE_SPI->SPI_RDR) & 0xFFFF); - - return incoming; -} - -// initialize -bool ISO7816_init(void) { - ISO7816_setup(); - - StartTicks(); - - // StopTicks(); -// return false; - - if ( MF_DBGLEVEL > 3 ) Dbprintf("ISO7816 OK"); - return true; -} - -void ISO7816_test(void) { - - if (!ISO7816_init()) return; - - ISO7816_stop(); -} - -void Iso7816_print_status(void) { - DbpString("Contact module (iso7816)"); - - if (!ISO7816_init()) { - DbpString(" init....................FAIL"); - return; - } - DbpString(" init....................OK"); - - ISO7816_stop(); -} \ No newline at end of file diff --git a/armsrc/iso7816.h b/armsrc/iso7816.h deleted file mode 100644 index 153b4723e..000000000 --- a/armsrc/iso7816.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef __ISO7816_H -#define __ISO7816_H - -#include "proxmark3.h" -#include "apps.h" -#include "ticks.h" - -#define ISO_CLK 75000000 //Hex equivalent of 75MHz - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// -extern void Dbprintf(const char *fmt, ...); - -void ISO7816_setup(void); -void ISO7816_stop(void); -bool ISO7816_waitidle(void); -uint16_t ISO7816_sendbyte(uint32_t data); -bool ISO7816_init(); -void ISO7816_test(void); -void Iso7816_print_status(void); -#endif \ No newline at end of file diff --git a/armsrc/smartcard.c b/armsrc/smartcard.c new file mode 100644 index 000000000..24de02a5f --- /dev/null +++ b/armsrc/smartcard.c @@ -0,0 +1,702 @@ +/************************************************************************************************** + * + * @project Proxmark 3 + * @file smartcard.c + * @author Chris Nocker + * @created 03/04/2018 + * @brief Implements communication with a smart card. + * + *************************************************************************************************/ +#include "smartcard.h" + +//#define SMART_CARD_DEBUG_ENABLED +#ifndef SMART_CARD_DEBUG_ENABLED + +#endif // SMART_CARD_DEBUG_ENABLED + +// -- Defines ---------------------------------------------------------------------------------- // +#define SMART_CARD_RST_PIN AT91C_PIO_PA1 +#define SMART_CARD_IO_PIN AT91C_PIO_PA5 +#define SMART_CARD_CLK_PIN AT91C_PIO_PA7 +#define SMART_CARD_RST_LO AT91C_BASE_PIOA->PIO_CODR |= SMART_CARD_RST_PIN +#define SMART_CARD_RST_HI AT91C_BASE_PIOA->PIO_SODR |= SMART_CARD_RST_PIN +#define SMART_CARD_RST_STATE AT91C_BASE_PIOA->PIO_ODSR & SMART_CARD_RST_PIN +#define SMART_CARD_IO_LO AT91C_BASE_PIOA->PIO_CODR |= SMART_CARD_IO_PIN +#define SMART_CARD_IO_HI AT91C_BASE_PIOA->PIO_SODR |= SMART_CARD_IO_PIN +#define SMART_CARD_IO_STATE AT91C_BASE_PIOA->PIO_ODSR & SMART_CARD_IO_PIN +#define SMART_CARD_CLK_LO AT91C_BASE_PIOA->PIO_CODR |= SMART_CARD_CLK_PIN +#define SMART_CARD_CLK_HI AT91C_BASE_PIOA->PIO_SODR |= SMART_CARD_CLK_PIN +#define SMART_CARD_CLK_STATE AT91C_BASE_PIOA->PIO_ODSR & SMART_CARD_CLK_PIN +#define SMART_CARD_IO_OUPUT_MODE AT91C_BASE_PIOA->PIO_OER = SMART_CARD_IO_PIN +#define SMART_CARD_IO_RECEPTION_MODE AT91C_BASE_PIOA->PIO_ODR = SMART_CARD_IO_PIN +#define SMART_CARD_RECEIVE_BUFFER_SIZE (10) +#define SMART_CARD_TRANSMIT_BUFFER_SIZE (10) + +// true = the distance between a and b is greater than c +#define RANGE(a,b,c) ((MAX(a,b))-(MIN(a,b))>(c)) + +// -- Private Variables ------------------------------------------------------------------------ // + +static bool triggerDeactivation; +static bool communicationsEstablished; +static uint16_t receiveBuffer[SMART_CARD_RECEIVE_BUFFER_SIZE]; // Raw received bytes that need their parity checked before using them +static uint8_t receiveGetPtr; +static uint8_t receivePutPtr; +static uint8_t transmitBuffer[SMART_CARD_TRANSMIT_BUFFER_SIZE]; +static uint8_t transmitGetPtr; +static uint8_t transmitPutPtr; +static bool generateClk; +static bool receptionMode; +static bool transmitMode; + +/** + * @brief Get a transmit byte + * @description Get a byte from the transmit buffer + * @param receivedByte Pointer to return the byte from the buffer to the caller + * @return bool true = A byte was removed from the buffer and returned to the caller + * false = No byte available + */ +static bool SMART_CARD_GetTransmitByte( uint8_t * receivedByte ) { + bool result = false; + uint8_t tempGetPtr = transmitGetPtr; + + // Move the temp put pointer to the next index + if ( ++tempGetPtr >= SMART_CARD_RECEIVE_BUFFER_SIZE ) { + tempGetPtr = 0; + } + + // If the get pointer does not match the put pointer then there is data to be taken from the buffer + if ( transmitGetPtr != transmitPutPtr ) { + *receivedByte = transmitBuffer[transmitGetPtr]; + transmitGetPtr = tempGetPtr; + result = true; + } + + return result; +} + +/** + * @brief Put transmit byte + * @description Store a byte in the transmit buffer + * @param transmitByte The byte to try and put in the buffer + * @return bool true = Operation was performed successfully + * false = No room in buffer :-( + */ +static bool SMART_CARD_PutTransmitByte( uint8_t transmitByte ) { + bool result = false; + uint8_t tempPutPtr = transmitPutPtr; + + // Move the temp put pointer to the next index + if ( ++tempPutPtr >= SMART_CARD_RECEIVE_BUFFER_SIZE ) { + tempPutPtr = 0; + } + + // If the new put pointer does not match the get pointer then it is safe to save this byte + if ( tempPutPtr != transmitGetPtr ) { + transmitBuffer[transmitPutPtr] = transmitByte; + transmitPutPtr = tempPutPtr; + result = true; + } + + return result; +} + +/** + * @brief Get received byte + * @description Get a byte from the receive buffer + * @param receivedByte Pointer to return the byte from the buffer to the caller + * @return bool true = A byte was removed from the buffer and returned to the caller + * false = No byte available + */ +static bool SMART_CARD_GetRecievedByte( uint16_t * receivedByte ) { + bool result = false; + uint8_t tempGetPtr = receiveGetPtr; + + // Move the temp put pointer to the next index + if ( ++tempGetPtr >= SMART_CARD_RECEIVE_BUFFER_SIZE ) { + tempGetPtr = 0; + } + + // If the get pointer does not match the put pointer then there is data to be taken from the buffer + if ( receiveGetPtr != receivePutPtr ) { + *receivedByte = receiveBuffer[receiveGetPtr]; + receiveGetPtr = tempGetPtr; + result = true; + } + + return result; +} + +/** + * @brief Put received byte + * @description Store a verified, received byte in the receive buffer + * @param receivedByte The byte to try and put in the buffer + * @return bool true = Operation was performed successfully + * false = No room in buffer :-( + */ +static bool SMART_CARD_PutRecievedByte( uint16_t receivedByte ) { + bool result = false; + uint8_t tempPutPtr = receivePutPtr; + + // Move the temp put pointer to the next index + if ( ++tempPutPtr >= SMART_CARD_RECEIVE_BUFFER_SIZE ) { + tempPutPtr = 0; + } + + // If the new put pointer does not match the get pointer then it is safe to save this byte + if ( tempPutPtr != receiveGetPtr ) { + receiveBuffer[receivePutPtr] = receivedByte; + receivePutPtr = tempPutPtr; + result = true; + } + + return result; +} + +/** + * @brief Calculate byte parity + * @description Calculate the parity of a byte + * @param dataByte Byte to calculate the parity of + * @return bool true = Parity of the byte is high + * false = Parity of the byte is low + */ +static bool SMART_CARD_CalculateByteParity( uint8_t dataByte ) { + bool result; + uint8_t i, parity; + + // Accumulate the parity + for ( i = 0, parity = 0; i < 8; i++ ) { + if ( dataByte & ( 1 << i ) ) { + parity++; + } + } + + // The high (1) bits of the byte plus the parity bit must be even for the byte to be considered as good + result = ( parity % 2 ) ? true : false; + + return result; +} + +/** + * @brief Verify received byte parity + * @description Calculate the parity of a received sampled byte and compare it to the parity in the received sampled byte + * @param receivedSampledByte Byte to verify the parity of + * @return bool true = Parity of the received byte is good + * false = Parity of the received byte is bad (reject) + */ +static bool SMART_CARD_VerifyReceivedByteParity( uint16_t receivedSampledByte ) { + bool result; + uint8_t dataByte = (uint8_t)(receivedSampledByte >> 1 ); + + // Check if the calculated parity is the same as the parity in the received sampled byte + if ( SMART_CARD_CalculateByteParity( dataByte ) == ( receivedSampledByte & 1 ) ) + result = true; + else + result = false; + + return result; +} + +/** + * @brief Maintain the smart card connection + * @description Send and receive commands + * @param void + * @return bool true = Operation was performed successfully + * false = An error occurred + */ +static bool SMART_CARD_MaintainConnection( void ) { + // TODO: This functions implementation is not yet complete + + bool result = true; + uint16_t rxByte; + uint8_t verifiedRxByte; + + // See if there has been a new byte sampled + if ( SMART_CARD_GetRecievedByte( &rxByte ) ) { + // Check that the parity is correct + if ( SMART_CARD_VerifyReceivedByteParity( rxByte ) ) { + verifiedRxByte = rxByte >> 1; + + // TODO: Dummy code that is to remove compiler warnings during development + if ( verifiedRxByte ) { + SMART_CARD_PutTransmitByte( verifiedRxByte ); + } + } + } + + return result; +} + +/** + * @brief Disable the clock + * @description + * @param void + * @return void + */ +static void SMART_CARD_DisableClock( void ) { + // Disable TC2 + AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKDIS; + generateClk = false; +} + +/** + * @brief Enable the clock + * @description + * @param void + * @return void + */ +static void SMART_CARD_EnableClock( void ) { + // Enable and reset TC2 + AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + generateClk = true; +} + +/** + * @brief Perform deactivation + * @description Control the signals to the smart card to perform a deactivation operation + * @param void + * @return bool true = Operation was performed successfully + * false = An error occurred + */ +static void SMART_CARD_PerformDeactivation( void ) { + /* + * 1. Reset L + * 2. CLK L + * 3. I/O L + * 4. VCC L (NOTE: This may require a circuit change!!!) + */ + SMART_CARD_RST_LO; + SMART_CARD_IO_LO; + SMART_CARD_DisableClock(); +} + +/** + * @brief Negotiate parameters + * @description + * @param void + * @return bool true = Operation was performed successfully + * false = An error occurred + */ +//static bool SMART_CARD_NegotiateProtocolParameters( void ) { +// TODO: This functions implementation is not yet complete +// bool result = false; +// +// // Check if the card is in a specific mode +// if ( 0xFF ) +// { +// // Have to use this mode +// } +// else +// { +// // Negotiate +// } +// +// return result; +//} + + +/** + * @brief Class selection + * @description Class selection + * @param void + * @return bool true = Operation was performed successfully + * false = An error occurred + */ +static bool SMART_CARD_ClassSelection( uint8_t class, uint8_t * answer, uint8_t length ) { + bool result = false; + + // Check that an answer was received + if ( answer[0] ) { + // Check that the answer was valid + if ( answer[1] ) { + // See if the card indicated a class + if ( answer[2] ) { + // Check that we are happy with the class (i.e. this is the 3V one that we supplied) + if ( answer[2] == 2 ) { + result = true; + } else { + // We cannot work with this class + triggerDeactivation = true; + } + } else { + // Card did not indicate class, just accept this answer + result = true; + } + } else { + // Error handling + } + } else { + // Card did not answer + triggerDeactivation = true; + } + return result; +} + + +/** + * @brief Process the reset answer + * @description + * @param answer + * @return bool true = Operation was performed successfully + * false = An error occurred + */ +static bool SMART_CARD_ProcessResetAnswer( uint8_t * answer, uint8_t length ) { + // TODO: This functions implementation is not yet complete + bool result = false; + uint8_t class; + + for ( class = 0; class < 3; class++ ) { + // We can only do one class as we cannot adjust the VCC voltage + if ( SMART_CARD_ClassSelection( class, answer, length ) ) { + result = true; + break; + } else { + if ( triggerDeactivation ) { + triggerDeactivation = false; + SMART_CARD_PerformDeactivation(); + } + } + } + + return result; +} + + +/** + * @brief Perform warm reset + * @description Can be performed at any time (not sure we'll use this one???) + * @param void + * @return bool true = Operation was performed successfully + * false = An error occurred + */ +//static bool SMART_CARD_PerformWarmReset( void ) { +// TODO: This functions implementation is not yet complete +// bool result = false; +// /* +// * 1. the interface device initiates a warm reset (at time Tc) by putting RST to state L for at least 400 clock cycles (delay te) while VCC remains powered and CLK provided +// * 2. The card shall set I/O to state H within 200 clock cycles (delay td) after state L is applied to RST +// * 3. RST is put to state H +// * 4. The answer on I/O shall begin between 400 and 40 000 clock cycles (delay tf) after the rising edge of the signal on RST +// * 5. If the answer does not begin within 40 000 clock cycles with RST at state H, the interface device shall perform a deactivation +// */ +// +// return result; +//} + +/** + * @brief Perform cold reset + * @description We are outputting the CLK to the smart card. Wait for the initial reset answer + * @param void + * @return bool true = Operation was performed successfully + * false = An error occurred + */ +static bool SMART_CARD_PerformColdReset( void ) { + // TODO: This functions implementation is not yet complete + bool result = false; + /* + * 1. The card shall set I/O to state H within 200 clock cycles + * The cold reset results from maintaining RST at state L for at least 400 clock cycles (delay tb) after the clock signal is applied to CLK + * 2. The interface device shall ignore the state on I/O while RST is at state L + * 3. RST is put to state H + * 4. The answer on I/O shall begin between 400 and 40 000 clock cycles (delay tc) after the rising edge of the signal on RST + * 5. If the answer does not begin within 40 000 clock cycles with RST at state H, the interface device shall perform a deactivation + */ + + return result; +} + +/** + * @brief Activate the smart card interface + * @description Control the interface signals to perform an activation on the smart card + * @param void + * @return void + */ +static void SMART_CARD_ActivateInterface( void ) { + /* + * 1. RST shall be put to state L + * 2. VCC shall be powered + * 3. I/O in the interface device shall be put in reception mode + * 4. CLK shall be provided with a clock signal (1MHz to 5MHz) + */ + SMART_CARD_RST_LO; + SMART_CARD_IO_RECEPTION_MODE; + SMART_CARD_EnableClock(); +} + +/** + * @brief Establish communications + * @description Activate the smart card, perform a cold reset & process the reset answer + * @param void + * @return bool true = Operation was performed successfully and communications have been established + * false = An error occurred + */ +static bool SMART_CARD_EstablishCommunications( void ) { + // TODO: This functions implementation is not yet complete + bool result = false; + uint8_t answer; + + // Activate the interface + SMART_CARD_ActivateInterface(); + + // Perform a cold reset + result = SMART_CARD_PerformColdReset(); + + // Process the "answer" if it was received + if ( result ) { + result = SMART_CARD_ProcessResetAnswer( &answer, 100 ); + + // Check if the "answer" was acceptable + if ( !result ) { + // Delay for 20ms + WaitMS( 20 ); + } + } + return result; +} + +/** + * @brief Configure timer + * @description Configure the timer to generate an interrupt every 500ns. This is 2MHz. From this we will + * generate the 1MHz clock signal and sample the I/O line every 2 interrupt triggers + * @param void + * @return void + */ +static void SMART_CARD_ConfigureClock( void ) { + AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC2); // Enable Clock TC2 + + AT91C_BASE_TCB->TCB_BMR &= AT91C_TCB_TC2XC2S; // Clear the external clock selection + AT91C_BASE_TCB->TCB_BMR |= AT91C_TCB_TC2XC2S_NONE; // XC2 Clock = None + + // Configure TC2 to count up to RC, then reset and generate an interrupt + AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKDIS; // Disable TC2 + AT91C_BASE_TC2->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK // TC2 Clock = MCK(48MHz)/2 = 24MHz + | AT91C_TC_CPCTRG; // Capture Mode, reset the TC2 counter when RC is reached + AT91C_BASE_TC2->TC_RC = 12; // RC Compare value = 24MHz / 2MHz = 12 + AT91C_BASE_TC2->TC_IER = AT91C_TC_CPCS; // Generate an interrupt when the RC value is reached +} + + +// -- Public Functions ------------------------------------------------------------------------- // + +/** + * @brief CLK interrupt handler + * + * @description Implements a bit banged CLK signal to the smart card. Also outputs data on the I/O line on rising + * CLK edges when transmiting and samples the I/O line on falling CLK edges when receiving + * @param void + * @return void + */ +void SMART_CARD_ClockInterruptHandler( void ) { + static uint8_t clkCount; + static uint8_t previousSampleRxClkCount; + static uint8_t previousSampleTxClkCount; + static uint16_t sampledRxData; // The bits of the Rx byte are accumulated here + static uint8_t sampleBitIndex; // Used during both Tx and Rx as the comms are half duplex + static uint8_t transmitByte; + bool sampleBit = SMART_CARD_IO_STATE; // Read the state of the I/O signal in case we are going to use it + + // Clear the interrupt + // TODO: This functions implementation is not yet complete... just need to handle the interrupt + + // Check if we are meant to be generating the CLK signal + if ( generateClk ) + { + // On the even clock counts we will toggle the CLK signal + if ( clkCount++ % 2 ) + { + // Read the current state of the CLK signal, if it is High then set it Low and if it is Low set it High + if ( SMART_CARD_CLK_STATE ) + { + // Generate a falling edge + SMART_CARD_CLK_LO; + + // ******************************************************************* // + // On the falling edge of the CLK signal we sample from the I/O signal // + // ******************************************************************* // + + // See if we are receiving + if ( receptionMode ) + { + // See if we are already looking for the start of a new byte OR + // It has been a while since we last captured a byte (this provides resynchronising) + if ( ( sampleBitIndex == 0 ) || ( RANGE( clkCount, previousSampleRxClkCount, 5 ) ) ) + { + sampleBitIndex = 0; + previousSampleRxClkCount = clkCount; + + // The start bit must be low + if ( sampleBit == 0 ) + { + // Set the bit index to indicate that we've detected a start bit + sampleBitIndex = 1; + + // Initialise the sample data byte where the received bits will be put + sampledRxData = 0; + } + } + // Otherwise see if we are in the process of collecting bits of a sample byte + else if ( ( sampleBitIndex ) && ( sampleBitIndex <= 10 ) ) + { + // Shift the bits of the sampled byte up by 1 to make room for this new bit + sampledRxData = sampledRxData << 1; + + // Or in the new sample bit + sampledRxData |= sampleBit << sampleBitIndex; + + // Check if we've received the start bit, 8 bits of the byte and the parity bit + if ( sampleBitIndex == 10 ) + { + // Transfer the sampled data into the receive buffer so that it can be processed + if ( !SMART_CARD_PutRecievedByte( sampledRxData ) ) + { + // An error has occured as there was no space to save this byte! + } + } + + // Increment index and wait for next bit + sampleBitIndex++; + + // Update the Rx CLK count so we know how long to wait + previousSampleRxClkCount = clkCount; + } + } + } + // CLK is Low so set it High + else + { + // Generate a rising edge + SMART_CARD_CLK_HI; + + // ***************************************************************************************** // + // On the rising edge of the CLK signal we output the next bit of the byte to the I/O signal // + // ***************************************************************************************** // + + // See if we are transmitting + if ( transmitMode ) + { + // See if we are already looking for new byte to transmit OR + // It has been a while since we last sent a byte (this allows for the "pause" time) + if ( ( sampleBitIndex == 0 ) || ( RANGE( clkCount, previousSampleTxClkCount, 7 ) ) ) + { + sampleBitIndex = 0; + previousSampleTxClkCount = clkCount; + + // See if there is a byte to transmit + if ( SMART_CARD_GetTransmitByte( &transmitByte ) ) + { + // The start bit must be low + SMART_CARD_IO_LO; + + // Set the bit index to indicate that we've started transmitting + sampleBitIndex = 1; + } + } + // We are in the process of collecting bits of a sample byte + else if ( ( sampleBitIndex ) && ( sampleBitIndex <= 11 ) ) + { + // Check if we've output the start bit and the 8 bits of the byte and the parity bit + if ( sampleBitIndex == 11 ) + { + // There is nothing left to output, set the I/O signal high during the "pause" time + SMART_CARD_IO_HI; + } + // Check if we've output the start bit and the 8 bits of the byte + else if ( sampleBitIndex == 10 ) + { + // Calculate the parity bit and output it appropriately + if ( SMART_CARD_CalculateByteParity( transmitByte ) ) + { + SMART_CARD_IO_HI; + } + else + { + SMART_CARD_IO_LO; + } + } + // Otherwise we are still outputting the bits of the byte + else + { + // Set the state of the I/O signal according to the bits of the transmit byte + if ( transmitByte & ( 1 << ( sampleBitIndex - 1 ) ) ) + { + SMART_CARD_IO_HI; + } + else + { + SMART_CARD_IO_LO; + } + } + + // Increment index for when the next bit is output + sampleBitIndex++; + } + } + } + } + } +} + + +/** + * @brief Service the smart card interface + * @description Check if a transaction needs to occur + * @param void + * @return bool true = The smart card was service successfully + * false = An error occurred + */ +void SMART_CARD_ServiceSmartCard( void ) { + + if ( !communicationsEstablished ) { + // Attempt to establish communications if they are not currently working + communicationsEstablished = SMART_CARD_EstablishCommunications(); + } else { + // Communications are working, processs any commands/responses + + // If a fatal error occurs we will need to re-establish communications + communicationsEstablished = SMART_CARD_MaintainConnection(); + } +} + +void SmartCard_setup(void) { + // Enable the pins to be controlled + AT91C_BASE_PIOA->PIO_PER = SMART_CARD_RST_PIN | SMART_CARD_CLK_PIN | SMART_CARD_IO_PIN; + + // Configure the pins to be outputs + AT91C_BASE_PIOA->PIO_OER = SMART_CARD_RST_PIN | SMART_CARD_CLK_PIN | SMART_CARD_IO_PIN; + + // Configure the IO pin for multi-drive mode (is this right?) + AT91C_BASE_PIOA->PIO_MDER = SMART_CARD_IO_PIN; + AT91C_BASE_PIOA->PIO_PPUER = SMART_CARD_IO_PIN; + + // Configure a timer to generate an interrupt for the clock signal and sampling of the I/O line + SMART_CARD_ConfigureClock(); +} + +void SmartCard_stop(void) { + StopTicks(); + if ( MF_DBGLEVEL > 3 ) Dbprintf("Smart Card Stop"); + LED_A_OFF(); +} + +bool SmartCard_init(void) { + + StartTicks(); + + LED_A_ON(); + SmartCard_setup(); + + if ( MF_DBGLEVEL > 3 ) Dbprintf("Smart Card Init OK"); + return true; +} + +void SmartCard_print_status(void) { + DbpString("Smart card module (ISO 7816)"); + + if (!SmartCard_init()) { + DbpString(" init....................FAIL"); + return; + } + DbpString(" init....................OK"); + + SmartCard_stop(); +} \ No newline at end of file diff --git a/armsrc/smartcard.h b/armsrc/smartcard.h new file mode 100644 index 000000000..4205e2ea9 --- /dev/null +++ b/armsrc/smartcard.h @@ -0,0 +1,17 @@ +#ifndef __SMARTCARD_H +#define __SMARTCARD_H + +#include "usb_cdc.h" +#include "proxmark3.h" +#include "apps.h" +#include "ticks.h" +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// +extern void Dbprintf(const char *fmt, ...); + +void SmartCard_setup(void); +void SmartCard_stop(void); +bool SmartCard_init(); + +void SMART_CARD_ServiceSmartCard( void ); +void SmartCard_print_status(void); +#endif \ No newline at end of file