The Smart Card Detective (SCD)
apps.c
Go to the documentation of this file.
00001 
00035 #include <avr/boot.h>
00036 #include <avr/io.h>
00037 #include <avr/sleep.h>
00038 #include <stdlib.h>
00039 #include <string.h>
00040 #include <util/delay.h>
00041 
00042 #include "apps.h"
00043 #include "emv.h"
00044 #include "emv_values.h"
00045 #include "scd.h"
00046 #include "scd_hal.h"
00047 #include "scd_io.h"
00048 #include "scd_logger.h"
00049 #include "scd_values.h"
00050 #include "serial.h"
00051 #include "terminal.h"
00052 #include "utils.h"
00053 #include "VirtualSerial.h"
00054 
00056 #define LCD_ENABLED 1                   
00057 
00059 #define DEBUG 0
00060 
00062 #define EEPROM_SIZE 4096
00063 
00065 #define BOOTLOADER_START_ADDRESS 0xF000
00066 
00068 #define TERMINAL_RESET_IO_WAIT (ETU_TERMINAL * 42000)
00069 
00070 /* Static variables */
00071 #if LCD_ENABLED
00072 static char* strDone = "All     Done";
00073 static char* strLog = "Writing Log";
00074 static char* strScroll = "BC to   scroll";
00075 static char* strDecide = "BA = yesBD = no";
00076 static char* strInsertCard = "Insert  card";
00077 static char* strCardInserted = "Card    inserted";
00078 static char* strTerminalReset = "Terminalreset";
00079 static char* strPINOK = "PIN OK";
00080 static char* strPINBAD = "PIN BAD";
00081 #endif
00082 
00088 uint8_t VirtualSerial(log_struct_t *logger)
00089 {
00090     char *buf;
00091     char *response = NULL;
00092 
00093     if(GetLCDState() == 0)
00094         InitLCD();
00095     fprintf(stderr, "\n");
00096 
00097     fprintf(stderr, "Set up  VS\n");
00098     _delay_ms(500);
00099     power_usb_enable();
00100     SetupHardware();
00101     sei();
00102 
00103     // Signal that VS is ready
00104     Led1On();
00105     Led2On();
00106     Led3On();
00107     Led4On();
00108     fprintf(stderr, "VS Ready\n");
00109     _delay_ms(100);
00110 
00111     for (;;)
00112     {
00113         buf = GetHostData(255);
00114         if(buf == NULL)
00115         {
00116             _delay_ms(100);
00117             continue;
00118         }
00119 
00120         response = (char*)ProcessSerialData(buf, logger);
00121         free(buf);
00122 
00123         if(response != NULL)
00124         {
00125             SendHostData(response);
00126             free(response);
00127             response = NULL;
00128         }
00129 
00130         // Need to switch back leds as some apps switch them off
00131         Led1On();
00132         Led2On();
00133         Led3On();
00134         Led4On();
00135         fprintf(stderr, "VS Ready\n");
00136     }
00137 }
00138 
00147 uint8_t SerialInterface(uint16_t baudUBRR, log_struct_t *logger)
00148 {
00149     char *buf;
00150     char *response = NULL;
00151 
00152     InitLCD();
00153     fprintf(stderr, "\n");
00154 
00155     fprintf(stderr, "Set up  Serial\n");
00156     _delay_ms(500);
00157     power_usart1_enable();
00158     _delay_ms(500);
00159     InitUSART(baudUBRR);
00160 
00161     fprintf(stderr, "Serial  Ready\n");
00162     _delay_ms(500);
00163 
00164     for (;;)
00165     {
00166         // Not working yet => resolder RX/TX and then try to enable/disable CTS/RTS signals
00167         fprintf(stderr, "Before  GetLine\n");
00168         _delay_ms(500);
00169         buf = GetLineUSART();
00170         if(buf == NULL)
00171         {
00172             _delay_ms(100);
00173             continue;
00174         }
00175 
00176         fprintf(stderr, "Got:%s\n", buf);
00177         _delay_ms(500);
00178 
00179         response = (char*)ProcessSerialData(buf, logger);
00180         free(buf);
00181 
00182         if(response != NULL)
00183         {
00184             SendLineUSART(response);
00185             free(response);
00186         }
00187     }
00188 }
00189 
00194 void EraseEEPROM()
00195 {
00196         uint8_t sreg, k;
00197     uint16_t eeaddr = 0;
00198         uint8_t eeclear[32] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
00199                                0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
00200                                0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
00201                                0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
00202 
00203         sreg = SREG;
00204         cli();
00205 
00206         // Write page by page using the block writing method
00207     for(k = 0; k < EEPROM_SIZE / 32; k++)
00208     {
00209         eeprom_update_block(eeclear, (void*)eeaddr, 32);
00210         eeaddr = eeaddr + 32;
00211     }
00212 
00213         SREG = sreg;
00214 }
00215 
00224 void ResetEEPROM()
00225 {
00226     EraseEEPROM();
00227 
00228     eeprom_write_byte((uint8_t*)EEPROM_WARM_RESET, 0);
00229     eeprom_write_dword((uint32_t*)EEPROM_TIMER_T2, 0);
00230     eeprom_write_dword((uint32_t*)EEPROM_TEMP_1, 0);
00231     eeprom_write_dword((uint32_t*)EEPROM_TEMP_2, 0);
00232     eeprom_write_byte((uint8_t*)EEPROM_APPLICATION, 0);
00233     eeprom_write_byte((uint8_t*)EEPROM_COUNTER, 0);
00234     eeprom_write_byte(
00235             (uint8_t*)EEPROM_TLOG_POINTER_HI, (EEPROM_TLOG_DATA >> 8) & 0xFF);
00236     eeprom_write_byte(
00237             (uint8_t*)EEPROM_TLOG_POINTER_LO, EEPROM_TLOG_DATA & 0xFF);
00238 }
00239 
00247 void RunBootloader()
00248 {
00249     bootkey = MAGIC_BOOT_KEY;
00250     EnableWDT(100);
00251     while(1);
00252 }
00253 
00254 
00258 uint8_t TestDDA(uint8_t convention, uint8_t TC1)
00259 {
00260    uint8_t status = 0;
00261    RAPDU *response = NULL;
00262    FCITemplate *fci = NULL;
00263    APPINFO *appInfo = NULL;
00264    RECORD *tData = NULL;
00265    ByteArray *offlineAuthData = NULL;
00266    ByteArray *ddata = NULL;
00267 
00268    EnableWDT(4000);
00269 
00270    // Select application
00271    //fci = ApplicationSelection(convention, TC1); // to use PSE first
00272    fci = SelectFromAID(convention, TC1, NULL, 0);
00273    if(fci == NULL)
00274    {
00275       fprintf(stderr, "Error\n");
00276       status = 1;
00277       goto endtransaction;
00278    }
00279    ResetWDT();
00280 
00281    // Start transaction by issuing Get Processing Opts command
00282    appInfo = InitializeTransaction(convention, TC1, fci, 0);
00283    if(appInfo == NULL)
00284    {
00285       fprintf(stderr, "Error\n");
00286       status = 1;
00287       goto endfci;
00288    }
00289    ResetWDT();
00290 
00291    // Get transaction data
00292    offlineAuthData = (ByteArray*)malloc(sizeof(ByteArray));
00293    tData = GetTransactionData(convention, TC1, appInfo, offlineAuthData, 0);
00294    if(tData == NULL)
00295    {
00296       fprintf(stderr, "Error\n");
00297       status = 1;
00298       goto endappinfo;
00299    }
00300    ResetWDT();
00301 
00302    // Send internal authenticate command
00303    ddata = MakeByteArrayV(4,
00304          0x05, 0x06, 0x07, 0x08
00305          );
00306    response = SignDynamicData(convention, TC1, ddata, 0);
00307    if(response == NULL)
00308    {
00309       fprintf(stderr, "Error\n");
00310       status = 1;
00311       goto endtdata;
00312    }
00313 
00314    FreeRAPDU(response);
00315    FreeByteArray(ddata);
00316 endtdata:
00317    FreeRECORD(tData);
00318 endappinfo:
00319    FreeAPPINFO(appInfo);
00320    if(offlineAuthData != NULL)
00321       FreeByteArray(offlineAuthData);
00322 endfci:
00323    FreeFCITemplate(fci);
00324 endtransaction:
00325    DeactivateICC();
00326    asm volatile("nop\n\t"::);
00327    _delay_ms(50);
00328 
00329    DisableWDT();
00330    return status;
00331 }
00332 
00333 
00342 uint8_t Terminal(log_struct_t *logger)
00343 {
00344    uint8_t convention, proto, TC1, TA3, TB3;
00345    uint8_t error;
00346    uint8_t tmp;
00347    RAPDU *response = NULL;
00348    FCITemplate *fci = NULL;
00349    APPINFO *appInfo = NULL;
00350    RECORD *tData = NULL;
00351    ByteArray *offlineAuthData = NULL;
00352    ByteArray *pinTryCounter = NULL;
00353    ByteArray *pin = NULL;
00354    ByteArray *ddata = NULL;
00355    ByteArray *bdata = NULL;
00356    ByteArray *atcData = NULL;
00357    ByteArray *lastAtcData = NULL;
00358    GENERATE_AC_PARAMS acParams;
00359    const TLV *cdol = NULL;
00360 
00361     // Visual signal for this app
00362     Led1Off();
00363     Led2On();
00364     Led3Off();
00365     Led4Off();
00366 
00367    if(!lcdAvailable) 
00368    {
00369        Led2Off();
00370        _delay_ms(500);
00371        Led2On();
00372        _delay_ms(500);
00373        Led2Off();
00374        return RET_ERROR;
00375    }
00376 
00377    if(GetLCDState() == 0)
00378        InitLCD();
00379    fprintf(stderr, "\n");
00380    fprintf(stderr, "Terminal\n");
00381    _delay_ms(500);
00382 
00383    DisableWDT();
00384    DisableTerminalResetInterrupt();
00385    DisableICCInsertInterrupt();
00386 
00387    // Expect the card to be inserted first and then start
00388    fprintf(stderr, "%s\n", strInsertCard);
00389    while(IsICCInserted() == 0);
00390    fprintf(stderr, "%s\n", strCardInserted);
00391    if(logger)
00392        LogByte1(logger, LOG_ICC_INSERTED, 0);
00393 
00394    EnableWDT(4000);
00395 
00396    // Initialize card
00397    error = ResetICC(0, &convention, &proto, &TC1, &TA3, &TB3, logger);
00398    if(error)
00399    {
00400        fprintf(stderr, "Error:  %d\n", error);
00401        _delay_ms(1000);
00402        goto endtransaction;
00403    }
00404    if(proto != 0)
00405    {
00406        error = RET_ICC_BAD_PROTO;
00407        fprintf(stderr, "Error:  %d\n", error);
00408        _delay_ms(1000);
00409        goto endtransaction;
00410    }
00411    ResetWDT();
00412 
00413    // Select application. You can use one of the following options:
00414    //
00415    // Option 1: use the PSE first. Use the line below:
00416    // fci = ApplicationSelection(convention, TC1, logger);
00417    //
00418    // Option 2: use a specific Application ID (AID). Use the lines below:
00419    // bdata = MakeByteArrayV(
00420    //        7, 0xA0, 0, 0, 0, 0x29, 0x10, 0x10);
00421    // fci = SelectFromAID(convention, TC1, bdata, logger);
00422    //
00423    // Option 3: use a predefined list (see terminal.c) of AIDs. Use this line:
00424    // fci = SelectFromAID(convention, TC1, NULL, logger);
00425    fci = SelectFromAID(convention, TC1, NULL, logger);
00426    if(fci == NULL)
00427    {
00428        error = RET_EMV_SELECT;
00429        fprintf(stderr, "Error:  %d\n", error);
00430        _delay_ms(1000);
00431        goto endtransaction;
00432    }
00433    ResetWDT();
00434 
00435    // Start transaction by issuing Get Processing Opts command
00436    appInfo = InitializeTransaction(convention, TC1, fci, logger);
00437    if(appInfo == NULL)
00438    {
00439        error = RET_EMV_INIT_TRANSACTION;
00440        fprintf(stderr, "Error:  %d\n", error);
00441        _delay_ms(1000);
00442        goto endfci;
00443    }
00444    ResetWDT();
00445 
00446    // Get transaction data
00447    // Be careful about the amount of memory used. If you are using the logger
00448    // then bear in mind how much memory you are using and how much is left.
00449    // If your logger uses around 3K (see scd_logger.h) then you probably won't
00450    // have enough memory to actually store more transaction data such as the
00451    // offlineAuthData. Pass NULL to the offlineAuthData, to the logger or reduce
00452    // the logger size (see scd_logger.h).
00453    // offlineAuthData = (ByteArray*)malloc(sizeof(ByteArray));
00454    offlineAuthData = NULL;
00455    tData = GetTransactionData(convention, TC1, appInfo, offlineAuthData, logger);
00456    if(tData == NULL)
00457    {
00458        error = RET_EMV_READ_DATA;
00459        fprintf(stderr, "Error:  %d\n", error);
00460        _delay_ms(1000);
00461        goto endappinfo;
00462    }
00463    ResetWDT();
00464 
00465    // Get ATC
00466    atcData = GetDataObject(convention, TC1, PDO_ATC, logger);
00467    ResetWDT();
00468 
00469    // Get Last online ATC
00470    lastAtcData = GetDataObject(convention, TC1, PDO_LAST_ATC, logger);
00471    ResetWDT();
00472 
00473    if(atcData)
00474    {
00475        fprintf(stderr, "atc: %d\n", (atcData->bytes[0] << 8) | atcData->bytes[1]);
00476        _delay_ms(1000);
00477    }
00478 
00479    if(lastAtcData)
00480    {
00481        fprintf(stderr, "last onlatc: %d\n", (lastAtcData->bytes[0] << 8) | lastAtcData->bytes[1]);
00482        _delay_ms(1000);
00483    }
00484 
00485    // Send internal authenticate command (only for DDA cards supporting as per AIP)
00486    if((appInfo->aip[0] & 0x20) != 0)
00487    {
00488       ddata = MakeByteArrayV(4,
00489             0x01, 0x02, 0x03, 0x04
00490             );
00491       response = SignDynamicData(convention, TC1, ddata, logger);
00492       if(response == NULL)
00493       {
00494          error = RET_EMV_DDA;
00495          fprintf(stderr, "Error:  %d\n", error);
00496          goto endatcdata;
00497       }
00498       ResetWDT();
00499    }
00500 
00501    // Get PIN try counter
00502    pinTryCounter = GetDataObject(convention, TC1, PDO_PIN_TRY_COUNTER, logger);
00503    if(pinTryCounter == NULL)
00504    {
00505        error = RET_EMV_GET_DATA;
00506        fprintf(stderr, "Error:  %d\n", error);
00507        goto endatcdata;
00508    }
00509    if(pinTryCounter->bytes[0] == 0)
00510    {
00511        error = RET_EMV_PIN_TRY_EXCEEDED;
00512        fprintf(stderr, "Error:  %d\n", error);
00513        goto endpintry;
00514    }
00515    ResetWDT();
00516 
00517    fprintf(stderr, "pin try:%d\n", pinTryCounter->bytes[0]);
00518    _delay_ms(1000);
00519    ResetWDT();
00520 
00521    /*
00522    // Send PIN verification
00523    // Below just an example for PIN=1234. Implement some pin entry mechanism
00524    // with buttons if needed
00525    pin = MakeByteArrayV(8, 0x24, 0x12, 0x34, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF);
00526    if(pin == NULL)
00527    {
00528       error = RET_ERROR;
00529       fprintf(stderr, "Error:  %d\n", error);
00530       goto endpintry;
00531    }
00532    DisableWDT();
00533    tmp = VerifyPlaintextPIN(convention, TC1, pin, logger);
00534    if(tmp == 0)
00535       fprintf(stderr, "%s\n", strPINOK);
00536    else
00537    {
00538       fprintf(stderr, "%s\n", strPINBAD);
00539       goto endpin;
00540    }
00541    EnableWDT(4000);
00542    */
00543 
00544    // Send the first GENERATE_AC command (amount = 0)
00545    acParams.tvr[0] = 0x80;
00546    acParams.terminalCountryCode[0] = 0x08;
00547    acParams.terminalCountryCode[1] = 0x26;
00548    acParams.terminalCurrencyCode[0] = 0x08;
00549    acParams.terminalCurrencyCode[1] = 0x26;
00550    acParams.transactionDate[0] = 0x01;
00551    acParams.transactionDate[1] = 0x01;
00552    acParams.transactionDate[2] = 0x01;
00553    cdol = GetTLVFromRECORD(tData, 0x8C, 0);
00554    if(cdol == NULL)
00555    {
00556       error = RET_ERROR;
00557       fprintf(stderr, "Error:  %d\n", error);
00558       _delay_ms(500);
00559       goto endpin;
00560    }
00561 
00562    if(response != NULL) FreeRAPDU(response);
00563    response = SendGenerateAC(
00564            convention, TC1, AC_REQ_ARQC, cdol, &acParams, logger);
00565    if(response == NULL)
00566    {
00567        error = RET_EMV_GENERATE_AC;
00568        fprintf(stderr, "Error:  %d\n", error);
00569        _delay_ms(500);
00570        goto endpin;
00571    }
00572 
00573    fprintf(stderr, "%s\n", strDone);
00574    error = 0;
00575    FreeRAPDU(response);
00576 endpin:
00577    //FreeByteArray(pin);
00578 endpintry:
00579    FreeByteArray(pinTryCounter);
00580 endatcdata:
00581    FreeByteArray(lastAtcData);
00582    FreeByteArray(atcData);
00583 endtdata:
00584    FreeRECORD(tData);
00585 endappinfo:
00586    FreeAPPINFO(appInfo);
00587    if(offlineAuthData != NULL)
00588       FreeByteArray(offlineAuthData);
00589 endfci:
00590    FreeFCITemplate(fci);
00591 endtransaction:
00592    DisableWDT();
00593    DeactivateICC();
00594 
00595    if(logger)
00596    {
00597        LogByte1(logger, LOG_ICC_DEACTIVATED, 0);
00598        fprintf(stderr, "%s\n", strLog);
00599        WriteLogEEPROM(logger);
00600        ResetLogger(logger);
00601    }
00602 
00603    return error;
00604 }
00605 
00606 
00623 uint8_t FilterGenerateAC(log_struct_t *logger)
00624 {
00625         uint8_t t_inverse = 0, t_TC1 = 0;
00626         uint8_t cInverse, cProto, cTC1, cTA3, cTB3;
00627         uint8_t tmp, error;
00628         uint8_t posCDOL1 = 0;
00629         uint8_t amount[12];     
00630         uint8_t gotGAC = 0;
00631         CAPDU *cmd;
00632         RAPDU *response;        
00633         RECORD *record;
00634         CRP *crp;
00635 
00636     if(!lcdAvailable) 
00637     {
00638        Led2On();
00639        _delay_ms(1000);
00640        Led2Off();
00641        return RET_ERROR;
00642     }
00643 
00644     InitLCD();
00645     fprintf(stderr, "\n");
00646     fprintf(stderr, "Filter  Gen AC\n");
00647     _delay_ms(1000);
00648 
00649     DisableWDT();
00650     DisableTerminalResetInterrupt();
00651     DisableICCInsertInterrupt();
00652 
00653     // Expect the card to be inserted first and then wait a for terminal reset
00654     fprintf(stderr, "%s\n", strInsertCard);
00655     while(IsICCInserted() == 0);
00656     fprintf(stderr, "%s\n", strCardInserted);
00657     if(logger)
00658        LogByte1(logger, LOG_ICC_INSERTED, 0);
00659     while(GetTerminalResetLine() != 0);
00660     fprintf(stderr, "%s\n", strTerminalReset);
00661     if(logger)
00662        LogByte1(logger, LOG_TERMINAL_RST_LOW, 0);
00663 
00664     EnableWDT(4000);
00665 
00666         error = InitSCDTransaction(t_inverse, t_TC1, &cInverse, 
00667             &cProto, &cTC1, &cTA3, &cTB3, logger);
00668         if(error)
00669                 goto enderror;
00670 
00671         // forward commands until Read Record is received
00672         while(posCDOL1 == 0)
00673         {
00674                 ResetWDT();
00675                 cmd = ReceiveT0Command(t_inverse, t_TC1, logger);
00676                 if(cmd == NULL)
00677         {
00678             error = RET_TERMINAL_GET_CMD;
00679             goto enderror;
00680         }
00681 
00682                 if((cmd->cmdHeader->cla & 0xF0) == 0 && 
00683                         cmd->cmdHeader->ins == 0xB2)
00684                 {                                               
00685                         // read record command
00686                         if(SendT0Command(cInverse, cTC1, cmd, logger))
00687                         {       
00688                 error = RET_ICC_SEND_CMD;
00689                                 FreeCAPDU(cmd);
00690                                 goto enderror;
00691                         }
00692 
00693                         response = ReceiveT0Response(cInverse, cmd->cmdHeader, logger);
00694                         if(response == NULL)
00695                         {       
00696                 error = RET_ICC_GET_RESPONSE;
00697                                 FreeCAPDU(cmd);
00698                                 goto enderror;
00699                         }
00700 
00701                         if(response->repData != NULL)
00702                         {
00703                                 record = ParseRECORD(response->repData, response->lenData);
00704                                 if(record == NULL)
00705                                 {
00706                     error = RET_ERROR;
00707                                         FreeCAPDU(cmd);
00708                                         FreeRAPDU(response);
00709                                         goto enderror;
00710                                 }
00711 
00712                                 posCDOL1 = AmountPositionInCDOLRecord(record);
00713                                 FreeRECORD(record);
00714                                 record = NULL;
00715                         }
00716 
00717                         if(SendT0Response(t_inverse, cmd->cmdHeader, response, logger))
00718                         {
00719                 error = RET_TERMINAL_SEND_RESPONSE;
00720                                 FreeCAPDU(cmd);
00721                                 FreeRAPDU(response);
00722                                 goto enderror;
00723                         }
00724                 }
00725                 else
00726                 {
00727                         // another command, just forward it
00728                         if(SendT0Command(cInverse, cTC1, cmd, logger))
00729                         {       
00730                 error = RET_ICC_SEND_CMD;
00731                                 FreeCAPDU(cmd);
00732                                 goto enderror;
00733                         }
00734 
00735                         response = ForwardResponse(t_inverse, cInverse, cmd->cmdHeader, logger);
00736                         if(response == NULL)
00737                         {
00738                 error = RET_ERROR;
00739                                 FreeCAPDU(cmd);
00740                             goto enderror;
00741                         }
00742 
00743                         // not interested in data
00744                         FreeCAPDU(cmd);
00745                         FreeRAPDU(response);
00746                 }       
00747         } //end while(posCDOL1 == 0)
00748 
00749         // Disable WDT as VERIFY command will delay
00750         DisableWDT();
00751 
00752         // forward commands but block first Generate AC command
00753         while(gotGAC == 0)
00754         {
00755                 cmd = ReceiveT0Command(t_inverse, t_TC1, logger);
00756                 if(cmd == NULL)
00757         {
00758             error = RET_TERMINAL_GET_CMD;
00759             goto enderror;
00760         }
00761 
00762                 if((cmd->cmdHeader->cla & 0xF0) == 0x80 && 
00763                         cmd->cmdHeader->ins == 0xAE)
00764                 {
00765                         // Generate AC command received
00766                         if(cmd->cmdData == NULL)
00767                         {
00768                 error = RET_ERROR;
00769                                 FreeCAPDU(cmd);
00770                                 goto enderror;
00771                         }
00772 
00773                         gotGAC = 1;
00774 
00775                         posCDOL1--; // the value in posCDOL1 started at 1
00776                         amount[0] = (cmd->cmdData[posCDOL1] & 0xF0) >> 4;
00777                         amount[1] = cmd->cmdData[posCDOL1] & 0x0F;
00778                         amount[2] = (cmd->cmdData[posCDOL1 + 1] & 0xF0) >> 4;
00779                         amount[3] = cmd->cmdData[posCDOL1 + 1] & 0x0F;
00780                         amount[4] = (cmd->cmdData[posCDOL1 + 2] & 0xF0) >> 4;
00781                         amount[5] = cmd->cmdData[posCDOL1 + 2] & 0x0F;
00782                         amount[6] = (cmd->cmdData[posCDOL1 + 3] & 0xF0) >> 4;
00783                         amount[7] = cmd->cmdData[posCDOL1 + 3] & 0x0F;
00784                         amount[8] = (cmd->cmdData[posCDOL1 + 4] & 0xF0) >> 4;
00785                         amount[9] = cmd->cmdData[posCDOL1 + 4] & 0x0F;
00786                         amount[10] = (cmd->cmdData[posCDOL1 + 5] & 0xF0) >> 4;
00787                         amount[11] = cmd->cmdData[posCDOL1 + 5] & 0x0F;
00788 
00789                         // block until user allows
00790                         // 500 ms is approx 5200 ETUs at a frequency of 4MHz. Thus
00791                         // do not use delays larger than 500 ms without requesting
00792                         // more time from terminal (byte 0x60) as the default maximum
00793                         // allowed response time is 9600 ETUs
00794 
00795                         while(1){
00796                                 fprintf(stderr, "%s\n", strScroll);
00797                                 do{
00798                                         tmp = GetButton();
00799                                         _delay_ms(100);                                 
00800                                         if(SendByteTerminalParity(0x60, t_inverse))
00801                                         {
00802                         error = RET_TERMINAL_SEND_RESPONSE;
00803                                                 FreeCAPDU(cmd);
00804                                                 goto enderror;
00805                                         }
00806                                 }while((tmp & BUTTON_C) == 0);  
00807                                 _delay_ms(100);                 
00808 
00809                                 fprintf(stderr, "Amt:%1X%1X%1X%1X%1X%1X%1X%1X%1X,%1X%1X\n",
00810                                         amount[1],
00811                                         amount[2],
00812                                         amount[3],
00813                                         amount[4],
00814                                         amount[5],
00815                                         amount[6],
00816                                         amount[7],
00817                                         amount[8],
00818                                         amount[9],
00819                                         amount[10],
00820                                         amount[11]);
00821 
00822                                 do{
00823                                         tmp = GetButton();
00824                                         _delay_ms(100);                                 
00825                                         if(SendByteTerminalParity(0x60, t_inverse))
00826                                         {
00827                         error = RET_TERMINAL_SEND_RESPONSE;
00828                                                 FreeCAPDU(cmd);
00829                                                 goto enderror;
00830                                         }
00831                                 }while((tmp & BUTTON_C) == 0);          
00832                                 _delay_ms(100);                                                 
00833 
00834                                 fprintf(stderr, "%s\n", strDecide);
00835                                 do{
00836                                         tmp = GetButton();
00837                                         _delay_ms(100);                                 
00838                                         if(SendByteTerminalParity(0x60, t_inverse))
00839                                         {
00840                         error = RET_TERMINAL_SEND_RESPONSE;
00841                                                 FreeCAPDU(cmd);
00842                                                 goto enderror;
00843                                         }
00844                                 }while(((tmp & BUTTON_A) == 0) && 
00845                                                 ((tmp & BUTTON_C) == 0) &&
00846                                                 ((tmp & BUTTON_D) == 0));
00847                                 _delay_ms(100);
00848 
00849                                 if((tmp & BUTTON_D) != 0)
00850                                 {
00851                                         return RET_ERROR; // transaction cancelled                                      
00852                                 }
00853 
00854                                 if((tmp & BUTTON_A) != 0) break; // continue transaction
00855                         } // while(1)
00856 
00857                 } // if((cmd->cmdHeader->cla & 0xF0) == 0 ...   
00858 
00859                 if(SendT0Command(cInverse, cTC1, cmd, logger))
00860                 {
00861             error = RET_ICC_SEND_CMD;
00862                         FreeCAPDU(cmd);
00863                         goto enderror;
00864                 }               
00865 
00866                 response = ForwardResponse(t_inverse, cInverse, cmd->cmdHeader, logger);
00867                 FreeCAPDU(cmd); 
00868 
00869                 if(response == NULL)
00870                 {
00871             error = RET_ERROR;
00872                         FreeRAPDU(response);
00873                         goto enderror;
00874                 }
00875                 FreeRAPDU(response);
00876         } //end while(gotGAC == 0)
00877 
00878     EnableWDT(4000);
00879         // continue rest of transaction until SCD is restarted by terminal reset
00880         while(1)
00881         {
00882                 crp = ExchangeCompleteData(t_inverse, cInverse, t_TC1, cTC1, logger);
00883                 if(crp == NULL)
00884         {
00885             error = RET_ERROR;
00886             goto enderror;
00887         }
00888                 FreeCRP(crp);   
00889                 ResetWDT();
00890         }       
00891 
00892         error = 0;
00893 
00894 enderror:
00895     DisableWDT();
00896     DeactivateICC();
00897     if(logger)
00898     {
00899         LogByte1(logger, LOG_ICC_DEACTIVATED, 0);
00900         WriteLogEEPROM(logger);
00901         fprintf(stderr, "%s\n", strLog);
00902         ResetLogger(logger);
00903     }
00904 
00905     return error;
00906 }
00907 
00926 uint8_t StorePIN(log_struct_t *logger)
00927 {
00928         uint8_t t_inverse = 0, t_TC1 = 0;
00929         uint8_t cInverse, cProto, cTC1, cTA3, cTB3;
00930         uint8_t tmp, len, error;
00931         CRP *crp;               
00932 
00933     if(lcdAvailable)
00934     {
00935         InitLCD();
00936         fprintf(stderr, "\n");
00937         fprintf(stderr, "Store   PIN\n");
00938         _delay_ms(1000);
00939     }
00940 
00941     DisableWDT();
00942     DisableTerminalResetInterrupt();
00943     DisableICCInsertInterrupt();
00944 
00945     // Expect the card to be inserted first and then wait a for terminal reset
00946     if(lcdAvailable)
00947         fprintf(stderr, "%s\n", strInsertCard);
00948     while(IsICCInserted() == 0);
00949     if(lcdAvailable)
00950         fprintf(stderr, "%s\n", strCardInserted);
00951     if(logger)
00952        LogByte1(logger, LOG_ICC_INSERTED, 0);
00953     while(GetTerminalResetLine() != 0);
00954     if(lcdAvailable)
00955         fprintf(stderr, "%s\n", strTerminalReset);
00956     if(logger)
00957        LogByte1(logger, LOG_TERMINAL_RST_LOW, 0);
00958         
00959         error = InitSCDTransaction(t_inverse, t_TC1, &cInverse, 
00960             &cProto, &cTC1, &cTA3, &cTB3, logger);
00961         if(error)
00962                 goto enderror;
00963 
00964         while(1)
00965         {
00966                 crp = ExchangeCompleteData(t_inverse, cInverse, t_TC1, cTC1, logger);
00967                 if(crp == NULL)
00968         {
00969             break;
00970         }
00971 
00972                 // check for verify command
00973                 if(crp->cmd->cmdHeader->cla == 0x00 &&
00974                          crp->cmd->cmdHeader->ins == 0x20)
00975                 {
00976                         // if PIN is not plaintext PIN then we abort
00977                         if(crp->cmd->cmdHeader->p2 != 0x80 || 
00978                                 crp->cmd->cmdData == NULL)
00979                         {                               
00980                                 error = RET_TERMINAL_ENCRYPTED_PIN;
00981                                 if(lcdAvailable)
00982                                         fprintf(stderr, "Error:  %d\n", error);
00983                 goto enderror;
00984                         }
00985                         
00986                         tmp = crp->cmd->cmdData[0];
00987                         len = crp->cmd->cmdHeader->p3;
00988                         if((tmp & 0xF0) != 0x20 || len != crp->cmd->lenData)
00989                         {
00990                 error = RET_ERROR;
00991                                 if(lcdAvailable)
00992                                         fprintf(stderr, "Error:  %d\n", error);
00993                                 error = RET_ERROR;
00994                 goto enderror;
00995                         }
00996 
00997                         // Write PIN command data to EEPROM
00998                         cli();
00999             eeprom_write_byte((uint8_t*)EEPROM_PIN, len);
01000                         eeprom_write_block(crp->cmd->cmdData, (void*)(EEPROM_PIN + 1), len);
01001 
01002                         // All done
01003                         if(lcdAvailable)
01004                                 fprintf(stderr, "PIN stored\n");
01005                 }
01006 
01007                 FreeCRP(crp);
01008         } // while(1)
01009 
01010     error = 0;
01011 
01012 enderror:
01013     DeactivateICC();
01014     if(logger)
01015     {
01016         LogByte1(logger, LOG_ICC_DEACTIVATED, 0);
01017         if(lcdAvailable)
01018             fprintf(stderr, "%s\n", strLog);
01019         WriteLogEEPROM(logger);
01020         ResetLogger(logger);
01021     }
01022 
01023         return error;
01024 }
01025 
01035 uint8_t ForwardAndChangePIN(log_struct_t *logger)
01036 {
01037         uint8_t t_inverse = 0, t_TC1 = 0, tdelay;
01038         uint8_t cInverse, cProto, cTC1, cTA3, cTB3;     
01039         CAPDU *cmd, *tcmd = NULL;
01040         RAPDU *response;        
01041         uint8_t sreg, len;
01042         uint8_t *pin;
01043     uint8_t error;
01044 
01045     if(lcdAvailable)
01046     {
01047         InitLCD();
01048         fprintf(stderr, "\n");
01049         fprintf(stderr, "Change  PIN\n");
01050         _delay_ms(1000);
01051     }
01052 
01053     DisableWDT();
01054     DisableTerminalResetInterrupt();
01055     DisableICCInsertInterrupt();
01056 
01057     // Expect the card to be inserted first and then wait a for terminal reset
01058     if(lcdAvailable)
01059         fprintf(stderr, "%s\n", strInsertCard);
01060     while(IsICCInserted() == 0);
01061     if(lcdAvailable)
01062         fprintf(stderr, "%s\n", strCardInserted);
01063     if(logger)
01064        LogByte1(logger, LOG_ICC_INSERTED, 0);
01065     while(GetTerminalResetLine() != 0);
01066     if(lcdAvailable)
01067         fprintf(stderr, "%s\n", strTerminalReset);
01068     if(logger)
01069        LogByte1(logger, LOG_TERMINAL_RST_LOW, 0);
01070 
01071         // read EEPROM PIN data
01072         sreg = SREG;
01073         cli();
01074         len = eeprom_read_byte((uint8_t*)EEPROM_PIN);
01075         SREG = sreg;
01076     pin = (uint8_t*)malloc(len * sizeof(uint8_t));
01077         if(pin == NULL)
01078     {
01079         error = RET_ERROR;      
01080         goto enderror;
01081     }
01082     eeprom_read_block(pin, (void*)(EEPROM_PIN + 1), len);
01083 
01084         error = InitSCDTransaction(t_inverse, t_TC1, &cInverse, 
01085             &cProto, &cTC1, &cTA3, &cTB3, logger);
01086         if(error)
01087     {
01088         if(lcdAvailable)
01089         {
01090             fprintf(stderr, "Error:  %d\n", error);
01091             _delay_ms(1000);
01092         }
01093                 goto enderror;
01094     }
01095 
01096         // forward commands and change VERIFY
01097         while(1)
01098         {
01099                 cmd = ReceiveT0Command(t_inverse, t_TC1, logger);
01100                 if(cmd == NULL)
01101         {
01102             error = RET_ERROR;
01103             goto enderror;
01104         }
01105 
01106                 // if PIN is plaintext then modify VERIFY command
01107                 if(cmd->cmdHeader->cla == 0 && 
01108                         cmd->cmdHeader->ins == 0x20 &&
01109                         cmd->cmdHeader->p2 == 0x80 &&
01110                         cmd->cmdData != NULL)
01111                 {       
01112                         // send modified VERIFY command
01113                         tdelay = 1 + cTC1;
01114                         tcmd = (CAPDU*)malloc(sizeof(CAPDU));
01115                         tcmd->cmdHeader = (EMVCommandHeader*)malloc(sizeof(EMVCommandHeader));
01116                         tcmd->cmdData = pin;
01117                         tcmd->lenData = len;
01118                         tcmd->cmdHeader->cla = cmd->cmdHeader->cla;
01119                         tcmd->cmdHeader->ins = cmd->cmdHeader->ins;
01120                         tcmd->cmdHeader->p1 = cmd->cmdHeader->p1;
01121                         tcmd->cmdHeader->p2 = cmd->cmdHeader->p2;
01122                         tcmd->cmdHeader->p3 = len;
01123                         
01124 
01125                         if(SendT0Command(cInverse, cTC1, tcmd, logger))
01126                         {
01127                 error = RET_ICC_SEND_CMD;
01128                                 FreeCAPDU(cmd);
01129                                 goto enderror;
01130                         }               
01131 
01132                         response = ForwardResponse(t_inverse, cInverse, tcmd->cmdHeader, logger);
01133                         if(response == NULL)
01134                         {
01135                 error = RET_ERROR;
01136                                 FreeCAPDU(cmd);                 
01137                                 FreeCAPDU(tcmd);
01138                                 goto enderror;
01139                         }       
01140 
01141                         FreeCAPDU(cmd); 
01142                         FreeCAPDU(tcmd);                
01143                         FreeRAPDU(response);                    
01144                 }
01145                 else            
01146                 {
01147                         if(SendT0Command(cInverse, cTC1, cmd, logger))
01148                         {       
01149                                 error = RET_ICC_SEND_CMD;
01150                                 FreeCAPDU(cmd);
01151                                 goto enderror;
01152                         }
01153 
01154                         response = ForwardResponse(t_inverse, cInverse, cmd->cmdHeader, logger);
01155                         if(response == NULL)
01156                         {
01157                                 error = RET_ERROR;
01158                                 FreeCAPDU(cmd);                                                 
01159                                 goto enderror;
01160                         }
01161                         
01162                         FreeCAPDU(cmd);                 
01163                         FreeRAPDU(response);
01164                 }                                       
01165                 
01166         } //end while(1)
01167 
01168     error = 0;
01169 
01170 enderror:
01171     DeactivateICC();
01172     if(logger)
01173     {
01174         LogByte1(logger, LOG_ICC_DEACTIVATED, 0);
01175         if(lcdAvailable)
01176             fprintf(stderr, "%s\n", strLog);
01177         WriteLogEEPROM(logger);
01178         ResetLogger(logger);
01179     }
01180 
01181         return error;
01182 }
01183 
01198 uint8_t ForwardData(log_struct_t *logger)
01199 {
01200         uint8_t t_inverse = 0, t_TC1 = 0, error = 0;
01201         uint8_t cInverse, cProto, cTC1, cTA3, cTB3;
01202     CRP *crp = NULL;
01203 
01204     // Visual signal for this app
01205     Led1On();
01206     Led2Off();
01207     Led3Off();
01208     Led4Off();
01209 
01210     if(lcdAvailable)
01211     {
01212         if(GetLCDState() == 0)
01213             InitLCD();
01214         fprintf(stderr, "\n");
01215                 fprintf(stderr, "Forward data\n");
01216         _delay_ms(500);
01217     }
01218 
01219     DisableWDT();
01220     DisableTerminalResetInterrupt();
01221     DisableICCInsertInterrupt();
01222 
01223     // Expect the card to be inserted first and then wait a for terminal reset
01224     if(lcdAvailable)
01225         fprintf(stderr, "%s\n", strInsertCard);
01226     while(IsICCInserted() == 0);
01227     if(lcdAvailable)
01228         fprintf(stderr, "Connect terminal\n");
01229     if(logger)
01230        LogByte1(logger, LOG_ICC_INSERTED, 0);
01231     while(GetTerminalResetLine() != 0);
01232     if(lcdAvailable)
01233                 fprintf(stderr, "Working ...\n");
01234     if(logger)
01235        LogByte1(logger, LOG_TERMINAL_RST_LOW, 0);
01236 
01237     error = InitSCDTransaction(t_inverse, t_TC1, &cInverse,
01238             &cProto, &cTC1, &cTA3, &cTB3, logger);
01239         if(error)
01240     {
01241         if(lcdAvailable)
01242         {
01243             fprintf(stderr, "Error:  %d\n", error);
01244             _delay_ms(1000);
01245         }
01246                 goto enderror;
01247     }
01248 
01249         // update transaction counter
01250         nCounter++;
01251 
01252         while(1)
01253         {
01254                 crp = ExchangeCompleteData(
01255                 t_inverse, cInverse, t_TC1, cTC1, logger);
01256                 if(crp == NULL)
01257             break;
01258         FreeCRP(crp);
01259         }
01260 
01261     error = 0;
01262 
01263 enderror:
01264     DeactivateICC();
01265     if(logger)
01266     {
01267         LogByte1(logger, LOG_ICC_DEACTIVATED, 0);
01268         if(lcdAvailable)
01269             fprintf(stderr, "%s\n", strLog);
01270         WriteLogEEPROM(logger);
01271         ResetLogger(logger);
01272     }
01273 
01274         return error;
01275 }
01276 
01287 uint8_t ForwardDataLogAC(log_struct_t *logger)
01288 {
01289         uint8_t t_inverse = 0, t_TC1 = 0;
01290         uint8_t cInverse, cProto, cTC1, cTA3, cTB3;
01291         uint8_t gotAC = 0, error = 0;
01292         CAPDU *cmd;
01293         RAPDU *response;        
01294         CRP *crp;
01295 
01296     if(lcdAvailable)
01297     {
01298         InitLCD();
01299         fprintf(stderr, "\n");
01300                 fprintf(stderr, "Forward Data2\n");
01301         _delay_ms(1000);
01302     }
01303 
01304     DisableWDT();
01305     DisableTerminalResetInterrupt();
01306     DisableICCInsertInterrupt();
01307 
01308     // Expect the card to be inserted first and then wait a for terminal reset
01309     if(lcdAvailable)
01310         fprintf(stderr, "%s\n", strInsertCard);
01311     while(IsICCInserted() == 0);
01312     if(lcdAvailable)
01313         fprintf(stderr, "%s\n", strCardInserted);
01314     if(logger)
01315        LogByte1(logger, LOG_ICC_INSERTED, 0);
01316     while(GetTerminalResetLine() != 0);
01317     if(lcdAvailable)
01318         fprintf(stderr, "%s\n", strTerminalReset);
01319     if(logger)
01320        LogByte1(logger, LOG_TERMINAL_RST_LOW, 0);
01321 
01322         
01323     error = InitSCDTransaction(t_inverse, t_TC1, &cInverse,
01324             &cProto, &cTC1, &cTA3, &cTB3, logger);
01325         if(error)
01326     {
01327         if(lcdAvailable)
01328         {
01329             fprintf(stderr, "Error:  %d\n", error);
01330             _delay_ms(1000);
01331         }
01332                 goto enderror;
01333     }
01334 
01335         // update transaction counter
01336         nCounter++;
01337 
01338         // forward data but don't log until we receive the generate AC
01339         while(gotAC == 0)
01340         {
01341                 cmd = ReceiveT0Command(t_inverse, t_TC1, NULL);
01342                 if(cmd == NULL)
01343         {
01344             error = RET_TERMINAL_GET_CMD;
01345             goto enderror;
01346         }
01347 
01348                 if((cmd->cmdHeader->cla & 0xF0) == 0x80 &&
01349                         cmd->cmdHeader->ins == 0xAE)
01350                 {                                               
01351                         // Generate AC command
01352             gotAC = 1;
01353                 }
01354 
01355         if(gotAC)
01356             error = SendT0Command(cInverse, cTC1, cmd, logger);
01357         else
01358             error = SendT0Command(cInverse, cTC1, cmd, NULL);
01359         if(error)
01360         {       
01361             error = RET_ICC_SEND_CMD;
01362             FreeCAPDU(cmd);
01363             goto enderror;
01364         }
01365 
01366         if(gotAC)
01367             response = ForwardResponse(t_inverse, cInverse, cmd->cmdHeader, logger);
01368         else
01369             response = ForwardResponse(t_inverse, cInverse, cmd->cmdHeader, NULL);
01370         if(response == NULL)
01371         {
01372             error = RET_ERROR;
01373             FreeCAPDU(cmd);
01374             goto enderror;
01375         }
01376 
01377         FreeCAPDU(cmd);
01378         FreeRAPDU(response);
01379         } //end while(gotAC == 0)
01380 
01381     // continue rest of transaction until we see a terminal reset
01382     while(1)
01383     {
01384         crp = ExchangeCompleteData(
01385                 t_inverse, cInverse, t_TC1, cTC1, logger);
01386         if(crp == NULL)
01387             break;
01388         FreeCRP(crp);   
01389     }   
01390 
01391     error = 0;
01392 
01393 enderror:
01394     DeactivateICC();
01395     if(logger)
01396     {
01397         LogByte1(logger, LOG_ICC_DEACTIVATED, 0);
01398         if(lcdAvailable)
01399             fprintf(stderr, "%s\n", strLog);
01400         WriteLogEEPROM(logger);
01401         ResetLogger(logger);
01402     }
01403 
01404         return error;
01405 }
01406 
01407 
01417 void WriteLogEEPROM(log_struct_t *logger)
01418 {
01419         uint16_t addrStream, write_size;
01420         uint8_t addrHi, addrLo;
01421 
01422     if(logger == NULL)
01423         return;
01424 
01425     // Visual signal for this app
01426     Led1Off();
01427     Led2Off();
01428     Led3On();
01429     Led4Off();
01430 
01431         // Update transaction counter in case it was modified
01432     eeprom_write_byte((uint8_t*)EEPROM_COUNTER, nCounter);
01433 
01434         // Get current transaction log pointer
01435         addrHi = eeprom_read_byte((uint8_t*)EEPROM_TLOG_POINTER_HI);
01436         addrLo = eeprom_read_byte((uint8_t*)EEPROM_TLOG_POINTER_LO);
01437         addrStream = ((addrHi << 8) | addrLo);
01438 
01439         if(logger->position > 0 && addrStream < EEPROM_MAX_ADDRESS)
01440         {
01441         // copy all possible data from log structure to EEPROM
01442         if(EEPROM_MAX_ADDRESS - addrStream < logger->position)
01443             write_size = EEPROM_MAX_ADDRESS - addrStream;
01444         else
01445             write_size = logger->position;
01446         eeprom_write_block(logger->log_buffer, (void*)addrStream, write_size);
01447         addrStream += write_size;
01448 
01449                 // update log address
01450                 addrHi = (uint8_t)((addrStream >> 8) & 0x00FF);
01451                 addrLo = (uint8_t)(addrStream & 0x00FF);
01452         eeprom_write_byte((uint8_t*)EEPROM_TLOG_POINTER_HI, addrHi);
01453         eeprom_write_byte((uint8_t*)EEPROM_TLOG_POINTER_LO, addrLo);
01454         }
01455 
01456     Led3Off();
01457 }
01458 
01459 
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Defines