SAMV71 Xplained Ultra Software Package 1.5

iso7816_4.c

Go to the documentation of this file.
00001 /* ---------------------------------------------------------------------------- */
00002 /*                  Atmel Microcontroller Software Support                      */
00003 /*                       SAM Software Package License                           */
00004 /* ---------------------------------------------------------------------------- */
00005 /* Copyright (c) 2015, Atmel Corporation                                        */
00006 /*                                                                              */
00007 /* All rights reserved.                                                         */
00008 /*                                                                              */
00009 /* Redistribution and use in source and binary forms, with or without           */
00010 /* modification, are permitted provided that the following condition is met:    */
00011 /*                                                                              */
00012 /* - Redistributions of source code must retain the above copyright notice,     */
00013 /* this list of conditions and the disclaimer below.                            */
00014 /*                                                                              */
00015 /* Atmel's name may not be used to endorse or promote products derived from     */
00016 /* this software without specific prior written permission.                     */
00017 /*                                                                              */
00018 /* DISCLAIMER:  THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR   */
00019 /* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */
00020 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE   */
00021 /* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,      */
00022 /* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
00023 /* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,  */
00024 /* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF    */
00025 /* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING         */
00026 /* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, */
00027 /* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                           */
00028 /* ---------------------------------------------------------------------------- */
00029 
00030 /**
00031  * \file
00032  *
00033  * \section Purpose
00034  *
00035  * ISO 7816 driver
00036  *
00037  * \section Usage
00038  *
00039  * Explanation on the usage of the code made available through the header file.
00040  */
00041 
00042 /*------------------------------------------------------------------------------
00043  *         Headers
00044  *----------------------------------------------------------------------------*/
00045 
00046 #include "board.h"
00047 
00048 /*------------------------------------------------------------------------------
00049  *         Definitions
00050  *----------------------------------------------------------------------------*/
00051 /** Case for APDU commands*/
00052 #define CASE1  1
00053 #define CASE2  2
00054 #define CASE3  3
00055 
00056 /** Flip flop for send and receive char */
00057 #define USART_SEND 0
00058 #define USART_RECEIVE  1
00059 
00060 #define USART7816BAUDRATE 9600
00061 /*-----------------------------------------------------------------------------
00062  *          Internal variables
00063  *---------------------------------------------------------------------------*/
00064 /** Variable for state of send and receive from USART */
00065 static uint8_t StateUsartGlobal = USART_RECEIVE;
00066 /** Pin reset master card */
00067 static Pin st_pinIso7816RstMC;
00068 static Usart *UsartIso;
00069 static uint32_t UsartIsoId;
00070 
00071 /*----------------------------------------------------------------------------
00072  *          Internal functions
00073  *----------------------------------------------------------------------------*/
00074 
00075 /**
00076  * Get a character from ISO7816
00077  * \param pCharToReceive Pointer for store the received char
00078  * \return 0: if timeout else status of US_CSR
00079  */
00080 static uint32_t ISO7816_GetChar(uint8_t *pCharToReceive)
00081 {
00082     uint32_t status;
00083     uint32_t timeout = 0;
00084 
00085     if (StateUsartGlobal == USART_SEND) {
00086         while ((UsartIso->US_CSR & US_CSR_TXEMPTY) == 0) {}
00087 
00088         UsartIso->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
00089         StateUsartGlobal = USART_RECEIVE;
00090     }
00091 
00092     /* Wait USART ready for reception */
00093     while (((UsartIso->US_CSR & US_CSR_RXRDY) == 0)) {
00094         if (timeout++ > 12000 * (BOARD_MCK / 1000000)) {
00095             TRACE_DEBUG("TimeOut\n\r");
00096             return (0);
00097         }
00098     }
00099 
00100     TRACE_DEBUG("T: %u\n\r", timeout);
00101 
00102 
00103     /* At least one complete character has been received and US_RHR has not
00104     yet been read. */
00105 
00106     /* Get a char */
00107     *pCharToReceive = ((UsartIso->US_RHR) & 0xFF);
00108 
00109     status = (UsartIso->US_CSR & (US_CSR_OVRE | US_CSR_FRAME |
00110                                   US_CSR_PARE | US_CSR_TIMEOUT | US_CSR_NACK |
00111                                   (1 << 10)));
00112 
00113     if (status != 0) {
00114         /* TRACE_DEBUG("R:0x%X\n\r", status); */
00115         TRACE_DEBUG("R:0x%X\n\r", UsartIso->US_CSR);
00116         TRACE_DEBUG("Nb:0x%X\n\r", UsartIso->US_NER);
00117         UsartIso->US_CR = US_CR_RSTSTA;
00118     }
00119 
00120     /* Return status */
00121     return (status);
00122 }
00123 
00124 /**
00125  * Send a char to ISO7816
00126  * \param CharToSend char to be send
00127  * \return status of US_CSR
00128  */
00129 static uint32_t ISO7816_SendChar(uint8_t CharToSend)
00130 {
00131     uint32_t status;
00132 
00133     if (StateUsartGlobal == USART_RECEIVE) {
00134         UsartIso->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
00135         StateUsartGlobal = USART_SEND;
00136     }
00137 
00138     /* Wait USART ready for transmit */
00139     while ((UsartIso->US_CSR & US_CSR_TXRDY) == 0)  {}
00140 
00141     /* There is no character in the US_THR */
00142 
00143     /* Transmit a char */
00144     UsartIso->US_THR = CharToSend;
00145 
00146     status = (UsartIso->US_CSR & (US_CSR_OVRE | US_CSR_FRAME |
00147                                   US_CSR_PARE | US_CSR_TIMEOUT | US_CSR_NACK |
00148                                   (1 << 10)));
00149 
00150     if (status != 0) {
00151         TRACE_DEBUG("E:0x%X\n\r", UsartIso->US_CSR);
00152         TRACE_DEBUG("Nb:0x%X\n\r", UsartIso->US_NER);
00153         UsartIso->US_CR = US_CR_RSTSTA;
00154     }
00155 
00156     /* Return status */
00157     return (status);
00158 }
00159 
00160 
00161 /**
00162  *  Iso 7816 ICC power on
00163  */
00164 static void ISO7816_IccPowerOn(void)
00165 {
00166     /* Set RESET Master Card */
00167     PIO_Set(&st_pinIso7816RstMC);
00168 }
00169 
00170 /*----------------------------------------------------------------------------
00171  *          Exported functions
00172  *----------------------------------------------------------------------------*/
00173 
00174 /**
00175  *  Iso 7816 ICC power off
00176  */
00177 void ISO7816_IccPowerOff(void)
00178 {
00179     /* Clear RESET Master Card */
00180     PIO_Clear(&st_pinIso7816RstMC);
00181 }
00182 
00183 /**
00184  * Transfer Block TPDU T=0
00185  * \param pAPDU    APDU buffer
00186  * \param pMessage Message buffer
00187  * \param wLength  Block length
00188  * \return         Message index
00189  */
00190 uint16_t ISO7816_XfrBlockTPDU_T0(const uint8_t *pAPDU,
00191                                  uint8_t *pMessage,
00192                                  uint16_t wLength)
00193 {
00194     uint16_t NeNc;
00195     uint16_t indexApdu = 4;
00196     uint16_t indexMessage = 0;
00197     uint8_t SW1 = 0;
00198     uint8_t procByte = 0;
00199     uint8_t cmdCase;
00200     uint8_t ins;
00201 
00202     TRACE_DEBUG("pAPDU[0]=0x%X\n\r", pAPDU[0]);
00203     TRACE_DEBUG("pAPDU[1]=0x%X\n\r", pAPDU[1]);
00204     TRACE_DEBUG("pAPDU[2]=0x%X\n\r", pAPDU[2]);
00205     TRACE_DEBUG("pAPDU[3]=0x%X\n\r", pAPDU[3]);
00206     TRACE_DEBUG("pAPDU[4]=0x%X\n\r", pAPDU[4]);
00207     TRACE_DEBUG("wlength=%d\n\r", wLength);
00208 
00209     ISO7816_SendChar(pAPDU[0]); /* CLA */
00210     ISO7816_SendChar(pAPDU[1]); /* INS */
00211     ISO7816_SendChar(pAPDU[2]); /* P1 */
00212     ISO7816_SendChar(pAPDU[3]); /* P2 */
00213     ISO7816_SendChar(pAPDU[4]); /* P3 */
00214 
00215     /* Handle the four structures of command APDU */
00216     indexApdu = 4;
00217 
00218     if (wLength == 4) {
00219         cmdCase = CASE1;
00220         NeNc = 0;
00221     } else if (wLength == 5) {
00222         cmdCase = CASE2;
00223         NeNc = pAPDU[4]; /* C5 */
00224 
00225         if (NeNc == 0)
00226             NeNc = 256;
00227     } else if (wLength == 6) {
00228         NeNc = pAPDU[4]; /* C5 */
00229         cmdCase = CASE3;
00230     } else if (wLength == 7) {
00231         NeNc = pAPDU[4]; /* C5 */
00232 
00233         if (NeNc == 0) {
00234             cmdCase = CASE2;
00235             NeNc = (pAPDU[5] << 8) + pAPDU[6];
00236         } else
00237             cmdCase = CASE3;
00238     } else {
00239         NeNc = pAPDU[4]; /* C5 */
00240 
00241         if (NeNc == 0) {
00242             cmdCase = CASE3;
00243             NeNc = (pAPDU[5] << 8) + pAPDU[6];
00244         } else
00245             cmdCase = CASE3;
00246     }
00247 
00248     TRACE_DEBUG("CASE=0x%X NeNc=0x%X\n\r", cmdCase, NeNc);
00249 
00250     /* Handle Procedure Bytes */
00251     do {
00252         ISO7816_GetChar(&procByte);
00253         ins = procByte ^ 0xff;
00254 
00255         /* Handle NULL */
00256         if (procByte == ISO_NULL_VAL) {
00257             TRACE_DEBUG("INS\n\r");
00258             continue;
00259         }
00260         /* Handle SW1 */
00261         else if (((procByte & 0xF0) == 0x60) || ((procByte & 0xF0) == 0x90)) {
00262             TRACE_DEBUG("SW1\n\r");
00263             SW1 = 1;
00264         }
00265         /* Handle INS */
00266         else if (pAPDU[1] == procByte) {
00267             TRACE_DEBUG("HdlINS\n\r");
00268 
00269             if (cmdCase == CASE2) {
00270                 /* receive data from card */
00271                 do {
00272                     ISO7816_GetChar(&pMessage[indexMessage++]);
00273                 } while (0 != --NeNc);
00274             } else {
00275                 /* Send data */
00276                 do {
00277                     ISO7816_SendChar(pAPDU[indexApdu++]);
00278                 } while (0 != --NeNc);
00279             }
00280         }
00281         /* Handle INS ^ 0xff */
00282         else if (pAPDU[1] == ins) {
00283             TRACE_DEBUG("HdlINS+\n\r");
00284 
00285             if (cmdCase == CASE2) {
00286                 /* receive data from card */
00287                 ISO7816_GetChar(&pMessage[indexMessage++]);
00288             } else
00289                 ISO7816_SendChar(pAPDU[indexApdu++]);
00290 
00291             NeNc--;
00292         } else {
00293             /* ?? */
00294             TRACE_DEBUG("procByte=0x%X\n\r", procByte);
00295             break;
00296         }
00297     } while (NeNc != 0);
00298 
00299     /* Status Bytes */
00300     if (SW1 == 0) {
00301         ISO7816_GetChar(&pMessage[indexMessage++]); /* SW1 */
00302     } else
00303         pMessage[indexMessage++] = procByte;
00304 
00305     ISO7816_GetChar(&pMessage[indexMessage++]); /* SW2 */
00306 
00307     return (indexMessage);
00308 
00309 }
00310 
00311 /**
00312  *  Escape ISO7816
00313  */
00314 void ISO7816_Escape(void)
00315 {
00316     TRACE_DEBUG("For user, if needed\n\r");
00317 }
00318 
00319 /**
00320  *  Restart clock ISO7816
00321  */
00322 void ISO7816_RestartClock(void)
00323 {
00324     TRACE_DEBUG("ISO7816_RestartClock\n\r");
00325     UsartIso->US_BRGR = 13;
00326 }
00327 
00328 /**
00329  *  Stop clock ISO7816
00330  */
00331 void ISO7816_StopClock(void)
00332 {
00333     TRACE_DEBUG("ISO7816_StopClock\n\r");
00334     UsartIso->US_BRGR = 0;
00335 }
00336 
00337 /**
00338  *  T0 APDU
00339  */
00340 void ISO7816_toAPDU(void)
00341 {
00342     TRACE_DEBUG("ISO7816_toAPDU\n\r");
00343     TRACE_DEBUG("Not supported at this time\n\r");
00344 }
00345 
00346 /**
00347  * Answer To Reset (ATR)
00348  * \param pAtr    ATR buffer
00349  * \param pLength Pointer for store the ATR length
00350  */
00351 void ISO7816_Datablock_ATR(uint8_t *pAtr, uint8_t *pLength)
00352 {
00353     uint32_t i;
00354     uint32_t j;
00355     uint32_t y;
00356 
00357     *pLength = 0;
00358 
00359     /* Read ATR TS */
00360     ISO7816_GetChar(&pAtr[0]);
00361     /* Read ATR T0 */
00362     ISO7816_GetChar(&pAtr[1]);
00363     y = pAtr[1] & 0xF0;
00364     i = 2;
00365 
00366     /* Read ATR Ti */
00367     while (y) {
00368         if (y & 0x10)    /* TA[i] */
00369             ISO7816_GetChar(&pAtr[i++]);
00370 
00371         if (y & 0x20)    /* TB[i] */
00372             ISO7816_GetChar(&pAtr[i++]);
00373 
00374         if (y & 0x40)    /* TC[i] */
00375             ISO7816_GetChar(&pAtr[i++]);
00376 
00377         if (y & 0x80) {  /* TD[i] */
00378             ISO7816_GetChar(&pAtr[i]);
00379             y =  pAtr[i++] & 0xF0;
00380         } else
00381             y = 0;
00382     }
00383 
00384     /* Historical Bytes */
00385     y = pAtr[1] & 0x0F;
00386 
00387     for (j = 0; j < y; j++)
00388         ISO7816_GetChar(&pAtr[i++]);
00389 
00390     *pLength = i;
00391 
00392 }
00393 
00394 /**
00395  * Set data rate and clock frequency
00396  * \param dwClockFrequency ICC clock frequency in KHz.
00397  * \param dwDataRate       ICC data rate in bpd
00398  */
00399 void ISO7816_SetDataRateandClockFrequency(uint32_t dwClockFrequency,
00400         uint32_t dwDataRate)
00401 {
00402     uint8_t ClockFrequency;
00403 
00404     /* Define the baud rate divisor register */
00405     /* CD  = MCK / SCK */
00406     /* SCK = FIDI x BAUD = 372 x 9600 */
00407     /* BOARD_MCK */
00408     /* CD = MCK/(FIDI x BAUD) = 48000000 / (372x9600) = 13 */
00409     UsartIso->US_BRGR = BOARD_MCK / (dwClockFrequency * 1000);
00410 
00411     ClockFrequency = BOARD_MCK / UsartIso->US_BRGR;
00412 
00413     UsartIso->US_FIDI = (ClockFrequency) / dwDataRate;
00414 
00415 }
00416 
00417 /**
00418  * Pin status for ISO7816 RESET
00419  * \return 1 if the Pin RstMC is high; otherwise 0.
00420  */
00421 uint8_t ISO7816_StatusReset(void)
00422 {
00423     return PIO_Get(&st_pinIso7816RstMC);
00424 }
00425 
00426 /**
00427  *  cold reset
00428  */
00429 void ISO7816_cold_reset(void)
00430 {
00431     volatile uint32_t i;
00432 
00433     /* tb: wait 400 cycles*/
00434     for (i = 0; i < (120 * (BOARD_MCK / 1000000)); i++) {
00435     }
00436 
00437     UsartIso->US_RHR;
00438     UsartIso->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
00439 
00440     ISO7816_IccPowerOn();
00441 }
00442 
00443 /**
00444  *  Warm reset
00445  */
00446 void ISO7816_warm_reset(void)
00447 {
00448     volatile uint32_t i;
00449 
00450     ISO7816_IccPowerOff();
00451 
00452     /* tb: wait 400 cycles */
00453     for (i = 0; i < (120 * (BOARD_MCK / 1000000)); i++) {
00454     }
00455 
00456     UsartIso->US_RHR;
00457     UsartIso->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
00458 
00459     ISO7816_IccPowerOn();
00460 }
00461 
00462 /**
00463  * Decode ATR trace
00464  * \param pAtr pointer on ATR buffer
00465  */
00466 void ISO7816_Decode_ATR(uint8_t *pAtr)
00467 {
00468     uint32_t i;
00469     uint32_t j;
00470     uint32_t y;
00471     uint8_t offset;
00472 
00473     printf("\n\r");
00474     printf("ATR: Answer To Reset:\n\r");
00475     printf("TS = 0x%X Initial character ", pAtr[0]);
00476 
00477     if (pAtr[0] == 0x3B)
00478 
00479         printf("Direct Convention\n\r");
00480     else {
00481         if (pAtr[0] == 0x3F)
00482             printf("Inverse Convention\n\r");
00483         else
00484             printf("BAD Convention\n\r");
00485     }
00486 
00487     printf("T0 = 0x%X Format character\n\r", pAtr[1]);
00488     printf("    Number of historical bytes: K = %d\n\r", pAtr[1] & 0x0F);
00489     printf("    Presence further interface byte:\n\r");
00490 
00491     if (pAtr[1] & 0x10)
00492         printf("TA ");
00493 
00494     if (pAtr[1] & 0x20)
00495         printf("TB ");
00496 
00497     if (pAtr[1] & 0x40)
00498         printf("TC ");
00499 
00500     if (pAtr[1] & 0x80)
00501         printf("TD ");
00502 
00503     if (pAtr[1] != 0)
00504         printf(" present\n\r");
00505 
00506     i = 2;
00507     y = pAtr[1] & 0xF0;
00508 
00509     /* Read ATR Ti */
00510     offset = 1;
00511 
00512     while (y) {
00513 
00514         if (y & 0x10) {  /* TA[i] */
00515             printf("TA[%d] = 0x%X ", offset, pAtr[i]);
00516 
00517             if (offset == 1) {
00518                 printf("FI = %d ", (pAtr[i] >> 4));
00519                 printf("DI = %d", (pAtr[i] & 0x0F));
00520             }
00521 
00522             printf("\n\r");
00523             i++;
00524         }
00525 
00526         if (y & 0x20) {  /* TB[i] */
00527             printf("TB[%d] = 0x%X\n\r", offset, pAtr[i]);
00528             i++;
00529         }
00530 
00531         if (y & 0x40) {  /* TC[i] */
00532             printf("TC[%d] = 0x%X ", offset, pAtr[i]);
00533 
00534             if (offset == 1)
00535                 printf("Extra Guard Time: N = %d", pAtr[i]);
00536 
00537             printf("\n\r");
00538             i++;
00539         }
00540 
00541         if (y & 0x80) {  /* TD[i] */
00542             printf("TD[%d] = 0x%X\n\r", offset, pAtr[i]);
00543             y =  pAtr[i++] & 0xF0;
00544         } else
00545             y = 0;
00546 
00547         offset++;
00548     }
00549 
00550     /* Historical Bytes */
00551     printf("Historical bytes:\n\r");
00552     y = pAtr[1] & 0x0F;
00553 
00554     for (j = 0; j < y; j++) {
00555         printf(" 0x%X", pAtr[i]);
00556 
00557         if ((pAtr[i] > 0x21) && (pAtr[i] < 0x7D))   /* ASCII */
00558             printf("(%c) ", pAtr[i]);
00559 
00560         i++;
00561     }
00562 
00563     printf("\n\r\n\r");
00564 
00565 }
00566 
00567 /** Initializes a ISO driver
00568  * \param pUsart   Pointer to the USART peripheral to configure.
00569  * \param usartId USART ID for iso7816
00570  *  \param pPinIso7816RstMC Pin ISO 7816 Rst MC
00571  */
00572 void ISO7816_Init(Usart *pUsart, uint32_t usartId ,
00573                    const Pin pPinIso7816RstMC)
00574 {
00575     TRACE_DEBUG("ISO_Init\n\r");
00576     UsartIso = pUsart;
00577     UsartIsoId = usartId;
00578     uint32_t baudrate = USART7816BAUDRATE;
00579 
00580     /* Pin ISO7816 initialize */
00581     st_pinIso7816RstMC  = pPinIso7816RstMC;
00582 
00583     PMC_EnablePeripheral(UsartIsoId);
00584 
00585     UsartIso->US_FIDI = 372;  /* by default */
00586 
00587     /* Configure USART */
00588     USART_Configure(UsartIso,
00589                      US_MR_USART_MODE_IS07816_T_0
00590                      | US_MR_USCLKS_MCK
00591                      | US_MR_NBSTOP_1_BIT
00592                      | US_MR_PAR_EVEN
00593                      | US_MR_CHRL_8_BIT
00594                      | US_MR_CLKO
00595                      | (3 << 24), /* MAX_ITERATION */
00596                      baudrate,
00597                      BOARD_MCK);
00598 
00599     /* Write the Time-guard Register */
00600     UsartIso->US_TTGR = 5;
00601 }
00602 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines