The Smart Card Detective (SCD)
terminal.c
Go to the documentation of this file.
00001 
00032 #include <string.h>
00033 #include <util/delay.h>
00034 #include <stdlib.h>
00035 
00036 #include "emv.h"
00037 #include "scd_hal.h"
00038 #include "terminal.h"
00039 #include "emv_values.h"
00040 #include "scd_values.h"
00041 #include "scd_io.h"
00042 
00044 #define DEBUG 1
00045 
00047 #define TRIGGER 1
00048 
00049 // ------------------------------------------------
00050 // Static declarations
00051 static RAPDU* TerminalSendT0CommandR(CAPDU* tmpCommand, RAPDU *tmpResponse,
00052    uint8_t inverse_convention, uint8_t TC1, log_struct_t *logger);
00053 
00054 //--------------------------------------------------------------------
00055 // Constants
00056 static const uint8_t nPSELen = 14;
00057 static const uint8_t bPSEString[14] = { '1', 'P', 'A', 'Y', '.', 'S', 'Y',
00058    'S', '.', 'D', 'D', 'F', '0', '1'};
00059 static const uint8_t nAIDLen = 7;
00060 static const uint8_t nAIDEntries = 6;
00061 static const uint8_t bAIDList[42] = {
00062    0xA0, 0, 0, 0, 0x29, 0x10, 0x10, // Link ATM
00063    0xA0, 0, 0, 0, 0x03, 0x10, 0x10, // Connect Debit VISA
00064    0xA0, 0, 0, 0, 0x04, 0x10, 0x10, // Connect Debit MasterCard
00065    0xA0, 0, 0, 0, 0x03, 0x80, 0x02, // CAP VISA
00066    0xA0, 0, 0, 0, 0x04, 0x80, 0x02, // CAP MasterCard
00067    0xA0, 0, 0, 0x02, 0x44, 0, 0x10  // Other App
00068 };
00069 
00070                                  
00071 
00072 // ------------------------------------------------
00073 // Public methods
00074 
00075 
00092 RAPDU* TerminalSendT0Command(
00093         CAPDU* cmd,
00094         uint8_t inverse_convention,
00095         uint8_t TC1,
00096         log_struct_t *logger)
00097 {
00098    CAPDU *tmpCommand;
00099 
00100    tmpCommand = CopyCAPDU(cmd);
00101    if(tmpCommand == NULL) return NULL;
00102 
00103    return TerminalSendT0CommandR(
00104            tmpCommand, NULL, inverse_convention, TC1, logger);
00105 }
00106 
00107 
00124 static RAPDU* TerminalSendT0CommandR(
00125         CAPDU *tmpCommand,
00126         RAPDU *tmpResponse,
00127         uint8_t inverse_convention,
00128         uint8_t TC1,
00129         log_struct_t *logger)
00130 {
00131    RAPDU *response, *tmp;
00132 
00133 #if TRIGGER
00134    // Make sure the trigger signals are low so we can watch them going high
00135    JTAG_P1_Low();
00136    JTAG_P3_Low();
00137 #endif
00138 
00139    LoopICCETU(16); // wait for card to be ready to receive new command
00140    
00141    if(SendT0Command(inverse_convention, TC1, tmpCommand, logger))
00142    {
00143       FreeRAPDU(tmpResponse);
00144       FreeCAPDU(tmpCommand);
00145       return NULL;
00146    }
00147 
00148 #if TRIGGER
00149    /* Code below used to create a trigger signal */
00150    if(TC1 > 0)
00151    {
00152        asm volatile("nop\n\t"::);
00153        JTAG_P1_High();
00154        if(TC1 == 2) JTAG_P3_High();
00155        _delay_ms(1);
00156 
00157        JTAG_P1_Low();
00158        if(TC1 == 2) JTAG_P3_Low();
00159    }
00160 #endif
00161 
00162    tmp = ReceiveT0Response(inverse_convention, tmpCommand->cmdHeader, logger);
00163 
00164    if(tmp == NULL || tmp->repStatus == NULL)
00165    {
00166       FreeRAPDU(tmpResponse);
00167       FreeCAPDU(tmpCommand);
00168       return NULL;
00169    }
00170 
00171    response = CopyRAPDU(tmp);
00172    if(response == NULL)
00173    {
00174       FreeRAPDU(tmpResponse);
00175       FreeRAPDU(tmp);
00176       FreeCAPDU(tmpCommand);
00177       return NULL;
00178    }
00179 
00180    // If there was already some data from an early response keep it.
00181    // else just keep the last response. In case this last response
00182    // is bad this will be seen in the status bytes
00183    if(tmpResponse != NULL && tmpResponse->repData != NULL &&
00184       tmpResponse->lenData != 0)
00185    {
00186       response->lenData = tmpResponse->lenData + tmp->lenData;
00187       response->repData = (uint8_t*)realloc(response->repData,
00188          (response->lenData) * sizeof(uint8_t));
00189       if(response->repData == NULL)
00190       {
00191          FreeRAPDU(tmpResponse);
00192          FreeRAPDU(tmp);
00193          FreeRAPDU(response);
00194          FreeCAPDU(tmpCommand);
00195          return NULL;
00196       }
00197       memcpy(response->repData, tmpResponse->repData, tmpResponse->lenData);
00198       memcpy(&(response->repData[tmpResponse->lenData]), tmp->repData, tmp->lenData);
00199    }
00200    FreeRAPDU(tmp);
00201    FreeRAPDU(tmpResponse);
00202 
00203    if(response->repStatus->sw1 == (uint8_t)SW1_MORE_DATA ||
00204       response->repStatus->sw1 == (uint8_t)SW1_WARNING1 ||
00205       response->repStatus->sw1 == (uint8_t)SW1_WARNING2)
00206    {
00207       FreeCAPDU(tmpCommand);
00208       CAPDU *cmdGet = MakeCommandC(CMD_GET_RESPONSE, NULL, 0);
00209       if(cmdGet == NULL)
00210       {
00211          FreeRAPDU(response);
00212          return NULL;
00213       }
00214       
00215       if(response->repStatus->sw1 == (uint8_t)SW1_MORE_DATA)
00216          cmdGet->cmdHeader->p3 = response->repStatus->sw2;
00217 
00218       return TerminalSendT0CommandR(
00219               cmdGet, response, inverse_convention, TC1, logger);
00220    }
00221    else if(response->repStatus->sw1 == (uint8_t)SW1_WRONG_LENGTH)
00222    {
00223       tmpCommand->cmdHeader->p3 = response->repStatus->sw2;
00224       return TerminalSendT0CommandR(
00225               tmpCommand, response, inverse_convention, TC1, logger);
00226    }
00227 
00228    // For any other result we return the APDU, which could be either success or not
00229    FreeCAPDU(tmpCommand);
00230    return response;
00231 }
00232 
00248 FCITemplate* ApplicationSelection(
00249         uint8_t convention,
00250         uint8_t TC1,
00251         const ByteArray *aid,
00252         uint8_t autoselect,
00253         log_struct_t *logger)
00254 {
00255     CAPDU* command;
00256     RAPDU* response;
00257     uint8_t sfi;
00258 
00259     // First try to select using PSE, else use list of AIDs
00260     command = MakeCommandC(CMD_SELECT, bPSEString, nPSELen);
00261     if(command == NULL) return NULL;
00262     response = TerminalSendT0Command(command, convention, TC1, logger);
00263     if(response == NULL)
00264     {
00265         FreeCAPDU(command);
00266         return NULL;
00267     }
00268     FreeCAPDU(command);
00269 
00270     if(response->repStatus->sw1 == 0x90 &&
00271          response->repStatus->sw2 == 0)
00272     {
00273         sfi = GetSFIFromSELECT(response);
00274         FreeRAPDU(response);
00275         return SelectFromPSE(convention, TC1, sfi, autoselect, logger);
00276     }
00277     else if((response->repStatus->sw1 == 0x6A && response->repStatus->sw2 == 0x82) ||
00278         (response->repStatus->sw1 == 0x62 && response->repStatus->sw2 == 0x83))
00279     {
00280         FreeRAPDU(response);
00281         return SelectFromAID(convention, TC1, aid, logger);
00282     }
00283 
00284     FreeRAPDU(response);
00285     return NULL;
00286 }
00287 
00301 APPINFO* InitializeTransaction(
00302         uint8_t convention,
00303         uint8_t TC1,
00304         const FCITemplate *fci,
00305         log_struct_t *logger)
00306 {
00307     TLV *pdol;
00308     ByteArray *data;
00309     CAPDU *command;
00310     RAPDU *response;
00311     APPINFO *appInfo;
00312 
00313     pdol = GetPDOL(fci);
00314     if(pdol == NULL) return NULL;
00315     pdol->tag1 = 0x83;
00316     pdol->tag2 = 0;
00317     data = SerializeTLV(pdol);
00318     if(data == NULL) return NULL;
00319 
00320     command = MakeCommandC(CMD_GET_PROCESSING_OPTS, data->bytes, data->len);
00321     FreeByteArray(data);
00322     if(command == NULL) return NULL;
00323     response = TerminalSendT0Command(command, convention, TC1, logger);
00324     if(response == NULL)
00325     {
00326         FreeCAPDU(command);
00327         return NULL;
00328     }
00329     FreeCAPDU(command);
00330 
00331     appInfo = ParseApplicationInfo(response->repData, response->lenData);
00332     FreeRAPDU(response);
00333 
00334     return appInfo;
00335 }
00336 
00353 RECORD* GetTransactionData(
00354         uint8_t convention,
00355         uint8_t TC1,
00356         const APPINFO* appInfo,
00357         ByteArray *offlineAuthData,
00358         log_struct_t *logger)
00359 {
00360    RECORD *data, *tmp;
00361    CAPDU *command;
00362    RAPDU *response;
00363    AFL* afl;
00364    uint8_t i, j, k, l;
00365 
00366    if(appInfo == NULL || appInfo->aflList == NULL) return NULL;
00367    data = (RECORD*)malloc(sizeof(RECORD));
00368    data->count = 0;
00369    data->objects = NULL;
00370 
00371    if(offlineAuthData != NULL)
00372    {
00373       offlineAuthData->len = 0;
00374       offlineAuthData->bytes = NULL;
00375    }
00376 
00377    command = MakeCommandC(CMD_READ_RECORD, NULL, 0);
00378    if(command == NULL)
00379    {
00380       free(data);
00381       return NULL;
00382    }
00383 
00384    for(i = 0; i < appInfo->count; i++)
00385    {
00386       afl = appInfo->aflList[i];
00387       if(afl == NULL) continue;
00388       
00389       for(j = afl->recordStart; j <= afl->recordEnd; j++)
00390       {
00391          command->cmdHeader->p1 = j;
00392          command->cmdHeader->p2 = (uint8_t)(afl->sfi | 4);
00393          response = TerminalSendT0Command(command, convention, TC1, logger);
00394          
00395          if(response == NULL || response->repStatus->sw1 != 0x90 || 
00396                response->repStatus->sw2 != 0)
00397          {
00398             if(response != NULL) FreeRAPDU(response);
00399             FreeRECORD(data);
00400             FreeCAPDU(command);
00401             return NULL;
00402          }
00403          if(response->repData == NULL || response->lenData < 2)
00404          {
00405             FreeRAPDU(response);
00406             continue;
00407          }
00408 
00409          // If there is data for offline authentication
00410          if(offlineAuthData != NULL && 
00411                (afl->recordsOfflineAuth > j - afl->recordStart))
00412          {
00413             if(afl->sfi > 0x50) // or ((afl->sfi >> 3) > 10)
00414             {
00415                k = response->lenData + offlineAuthData->len;
00416                offlineAuthData->bytes = 
00417                   (uint8_t*)realloc(offlineAuthData->bytes, k);
00418                if(offlineAuthData->bytes != NULL)
00419                {
00420                   memcpy(&offlineAuthData->bytes[offlineAuthData->len],
00421                         response->repData, response->lenData);
00422                   offlineAuthData->len = k;
00423                }
00424                else offlineAuthData->len = 0;
00425             }
00426             else
00427             {
00428                l = 2; // tag + length
00429                if(response->repData[1] == EMV_EXTRA_LENGTH_BYTE) l++;
00430                k = response->lenData - l + offlineAuthData->len;
00431                offlineAuthData->bytes = (uint8_t*)realloc(offlineAuthData->bytes, k);
00432                if(offlineAuthData->bytes != NULL)
00433                {
00434                   memcpy(&offlineAuthData->bytes[offlineAuthData->len],
00435                         &response->repData[l], response->lenData - l);
00436                   offlineAuthData->len += response->lenData - l;
00437                }
00438                else offlineAuthData->len = 0;
00439                
00440             }
00441          } // end if(offlineAuthData != NULL ...)
00442 
00443          tmp = ParseRECORD(response->repData, response->lenData);
00444          FreeRAPDU(response);
00445          if(AddRECORD(data, tmp))
00446          {
00447             FreeRECORD(data);
00448             FreeCAPDU(command);
00449             return NULL;
00450          }
00451          FreeRECORD(tmp);
00452       } // end for(j = afl->recordStart; j <= afl->recordEnd; j++)
00453    } // end for(i = 0; i < appInfo->count; i++)
00454    
00455    FreeCAPDU(command);
00456    return data;
00457 }
00458 
00459 
00477 FCITemplate* SelectFromAID(
00478         uint8_t convention,
00479         uint8_t TC1,
00480         const ByteArray *aid,
00481         log_struct_t *logger)
00482 {
00483    CAPDU* command;
00484    RAPDU* response;
00485    volatile uint8_t i = 0;
00486    FCITemplate* fci = NULL;
00487 
00488    if(aid != NULL && aid->len == nAIDLen)
00489    {
00490       command = MakeCommandC(CMD_SELECT, aid->bytes, nAIDLen);
00491       if(command == NULL) return NULL;
00492       response = TerminalSendT0Command(command, convention, TC1, logger);
00493       if(response == NULL)
00494       {
00495           FreeCAPDU(command);
00496           return NULL;
00497       }
00498       FreeCAPDU(command);
00499 
00500       if(response->repStatus->sw1 == 0x90 && response->repStatus->sw2 == 0)
00501       {
00502          fci = ParseFCI(response->repData, response->lenData);
00503          FreeRAPDU(response);
00504          return fci;
00505       }
00506 
00507       FreeRAPDU(response);
00508       return NULL;
00509    }
00510 
00511    while(i < nAIDEntries)
00512    {
00513       command = MakeCommandC(CMD_SELECT, &(bAIDList[nAIDLen * i]), nAIDLen);
00514       if(command == NULL) return NULL;
00515       response = TerminalSendT0Command(command, convention, TC1, logger);
00516       if(response == NULL)
00517       {
00518           FreeCAPDU(command);
00519           return NULL;
00520       }
00521 
00522       FreeCAPDU(command);
00523       if(response->repStatus->sw1 == 0x90 && response->repStatus->sw2 == 0)
00524       {
00525          fci = ParseFCI(response->repData, response->lenData);
00526          FreeRAPDU(response);
00527          return fci;
00528       }
00529       else if((response->repStatus->sw1 != 0x6A || response->repStatus->sw2 != 0x82) &&
00530             (response->repStatus->sw1 != 0x62 || response->repStatus->sw2 != 0x83))
00531       {
00532          FreeRAPDU(response);
00533          return NULL;
00534       }
00535 
00536       FreeRAPDU(response);
00537       i++;
00538    }
00539 
00540    return NULL;
00541 }
00542 
00558 FCITemplate* SelectFromPSE(
00559         uint8_t convention,
00560         uint8_t TC1,
00561         uint8_t sfiPSE,
00562         uint8_t autoselect,
00563         log_struct_t *logger)
00564 {
00565    FCITemplate* fci = NULL;
00566    CAPDU* command = NULL;
00567    RAPDU* response = NULL;
00568    RECORDList* rlist = NULL;
00569    TLV* adfName = NULL;
00570    uint8_t more, status, k, i;
00571    volatile uint8_t tmp;
00572 
00573    // Get the application list
00574    rlist = (RECORDList*)malloc(sizeof(RECORDList));
00575    if(rlist == NULL) goto clean;
00576    rlist->count = 0;
00577    rlist->objects = NULL;
00578    command = MakeCommandC(CMD_READ_RECORD, NULL, 0);
00579    if(command == NULL) goto clean;
00580    command->cmdHeader->p1 = 0;
00581    command->cmdHeader->p2 = (uint8_t)((sfiPSE << 3) | 4);
00582    more = 1;
00583 
00584    while(more)
00585    {
00586       more = 0;
00587       command->cmdHeader->p1 += 1;
00588       response = TerminalSendT0Command(command, convention, TC1, logger);
00589       if(response == NULL) goto clean;
00590       
00591       if(response->repData != NULL)
00592       {
00593          more = 1;
00594          status = ParsePSD(rlist, response->repData, response->lenData);
00595          if(status) goto clean;
00596       }
00597       FreeRAPDU(response);
00598       if(rlist == NULL) goto clean;
00599    }
00600    FreeCAPDU(command);
00601    command = NULL;
00602    if(rlist->count == 0) goto clean;
00603 
00604    k = 0;
00605    if(autoselect == 0)
00606    {
00607        while(1)
00608        {
00609            adfName = rlist->objects[k]->objects[0];
00610            fprintf(stderr, "%d:", k + 1);
00611            for(i = 0; i < adfName->len && i < 7; i++)
00612                fprintf(stderr, "%02X", adfName->value[i]);
00613            _delay_ms(200);
00614 
00615            do{
00616                tmp = GetButton();
00617            }while((tmp == 0));
00618 
00619            if((tmp & BUTTON_C))
00620            {
00621                k++;
00622                if(k == rlist->count) k = 0;
00623            }
00624            else 
00625            {
00626                break;
00627            }
00628        }
00629    }
00630 
00631    // select application, either by means of user or automatically
00632    // as here; modify as needed
00633    adfName = rlist->objects[k]->objects[0];
00634    command = MakeCommandC(CMD_SELECT, adfName->value, adfName->len);
00635    if(command == NULL) goto clean;
00636    response = TerminalSendT0Command(command, convention, TC1, logger);
00637    FreeCAPDU(command);
00638    command = NULL;
00639    if(response == NULL) goto clean;
00640    if(response->repData != NULL && response->repStatus->sw1 == SW1_COMPLETED)
00641       fci = ParseFCI(response->repData, response->lenData);
00642    FreeRAPDU(response);
00643 
00644 clean:
00645    if(command != NULL)
00646       FreeCAPDU(command);
00647    if(rlist != NULL)
00648       FreeRECORDList(rlist);
00649 
00650    return fci;
00651 }
00652 
00666 uint8_t VerifyPlaintextPIN(
00667         uint8_t convention,
00668         uint8_t TC1,
00669         const ByteArray *pin,
00670         log_struct_t *logger)
00671 {
00672     CAPDU* command;
00673     RAPDU* response;
00674 
00675     if(pin == NULL || pin->len == 0) return -1;
00676 
00677     command = MakeCommandC(CMD_VERIFY, pin->bytes, pin->len);
00678     if(command == NULL) return RET_ERROR;
00679     response = TerminalSendT0Command(command, convention, TC1, logger);
00680     if(response == NULL)
00681     {
00682         FreeCAPDU(command);
00683         return RET_ERROR;
00684     }
00685     FreeCAPDU(command);
00686 
00687     if(response->repStatus == NULL || response->repStatus->sw1 != 0x90 || 
00688          response->repStatus->sw2 != 0)
00689     {
00690         FreeRAPDU(response);
00691         return RET_ERROR;
00692     }
00693 
00694     FreeRAPDU(response);
00695     return 0;
00696 }
00697 
00717 RAPDU* SendGenerateAC(
00718         uint8_t convention,
00719         uint8_t TC1,
00720         AC_REQ_TYPE acType,
00721         const TLV* cdol,
00722         const GENERATE_AC_PARAMS *params,
00723         log_struct_t *logger)
00724 {
00725     CAPDU* command;
00726     RAPDU* response;
00727     uint8_t* data;
00728     uint8_t i, j, k, len;
00729     TLV* tlv;
00730 
00731     if(cdol == NULL || params == NULL) return NULL;
00732 
00733     // make the command data to be sent
00734     data = NULL;
00735     len = 0;
00736     i = 0;
00737     k = 0;
00738     while(k < cdol->len)
00739     {
00740         tlv = ParseTLV(&(cdol->value[k]), cdol->len - k, 0);
00741         k += 2;
00742         if(tlv == NULL) continue;
00743         if(tlv->tag2 != 0) k += 1;
00744         len += tlv->len;
00745         data = (uint8_t*)realloc(data, len * sizeof(uint8_t));
00746         if(data == NULL)
00747         {
00748             FreeTLV(tlv);
00749             return NULL;
00750         }
00751 
00752         if(tlv->tag1 == 0x9F && tlv->tag2 == 0x02)
00753         {
00754             for(j = 0; j < tlv->len && j < sizeof(params->amount); j++)
00755                 data[i++] = params->amount[j];
00756             while(j < tlv->len)
00757             {
00758                  data[i++] = 0;
00759                  j++;
00760             }
00761         }
00762         else if(tlv->tag1 == 0x9F && tlv->tag2 == 0x03) 
00763         {
00764             for(j = 0; j < tlv->len && j < sizeof(params->amountOther); j++)
00765              data[i++] = params->amountOther[j];
00766             while(j < tlv->len)
00767             {
00768              data[i++] = 0;
00769              j++;
00770             }
00771         }
00772         else if(tlv->tag1 == 0x9F && tlv->tag2 == 0x1A)
00773         {
00774             for(j = 0; j < tlv->len && j < sizeof(params->terminalCountryCode); j++)
00775                 data[i++] = params->terminalCountryCode[j];
00776              while(j < tlv->len)
00777              {
00778                 data[i++] = 0;
00779                 j++;
00780              }
00781         }
00782         else if(tlv->tag1 == 0x95)
00783         {
00784             for(j = 0; j < tlv->len && j < sizeof(params->tvr); j++)
00785                 data[i++] = params->tvr[j];
00786             while(j < tlv->len)
00787             {
00788                 data[i++] = 0;
00789                 j++;
00790             }
00791         }
00792       else if(tlv->tag1 == 0x5F && tlv->tag2 == 0x2A)
00793       {
00794          for(j = 0; j < tlv->len && j < sizeof(params->terminalCurrencyCode); j++)
00795             data[i++] = params->terminalCurrencyCode[j];
00796          while(j < tlv->len)
00797          {
00798             data[i++] = 0;
00799             j++;
00800          }
00801       }
00802       else if(tlv->tag1 == 0x8A)
00803       {
00804          for(j = 0; j < tlv->len && j < sizeof(params->arc); j++)
00805             data[i++] = params->arc[j];
00806          while(j < tlv->len)
00807          {
00808             data[i++] = 0;
00809             j++;
00810          }
00811       }
00812       else if(tlv->tag1 == 0x91)
00813       {
00814          for(j = 0; j < tlv->len && j < sizeof(params->IssuerAuthData); j++)
00815             data[i++] = params->IssuerAuthData[j];
00816          while(j < tlv->len)
00817          {
00818             data[i++] = 0;
00819             j++;
00820          }
00821       }
00822       else if(tlv->tag1 == 0x9A)
00823       {
00824          for(j = 0; j < tlv->len && j < sizeof(params->transactionDate); j++)
00825             data[i++] = params->transactionDate[j];
00826          while(j < tlv->len)
00827          {
00828             data[i++] = 0;
00829             j++;
00830          }
00831       }
00832       else if(tlv->tag1 == 0x9C)
00833       {
00834          data[i++] = params->transactionType;
00835       }
00836       else if(tlv->tag1 == 0x9F && tlv->tag2 == 0x37)
00837       {
00838          for(j = 0; j < tlv->len && j < sizeof(params->unpredictableNumber); j++)
00839             data[i++] = params->unpredictableNumber[j];
00840          while(j < tlv->len)
00841          {
00842             data[i++] = 0;
00843             j++;
00844          }
00845       }
00846       else if(tlv->tag1 == 0x9F && tlv->tag2 == 0x35)
00847       {
00848          data[i++] = params->terminalType;
00849       }
00850       else if(tlv->tag1 == 0x9F && tlv->tag2 == 0x45)
00851       {
00852          for(j = 0; j < tlv->len && j < sizeof(params->dataAuthCode); j++)
00853             data[i++] = params->dataAuthCode[j];
00854          while(j < tlv->len)
00855          {
00856             data[i++] = 0;
00857             j++;
00858          }
00859       }
00860       else if(tlv->tag1 == 0x9F && tlv->tag2 == 0x4C)
00861       {
00862          for(j = 0; j < tlv->len && j < sizeof(params->iccDynamicNumber); j++)
00863             data[i++] = params->iccDynamicNumber[j];
00864          while(j < tlv->len)
00865          {
00866             data[i++] = 0;
00867             j++;
00868          }
00869       }
00870       else if(tlv->tag1 == 0x9F && tlv->tag2 == 0x34)
00871       {
00872          for(j = 0; j < tlv->len && j < sizeof(params->cvmResults); j++)
00873             data[i++] = params->cvmResults[j];
00874          while(j < tlv->len)
00875          {
00876             data[i++] = 0;
00877             j++;
00878          }
00879       }
00880       else  // any other data
00881       {
00882          for(j = 0; j < tlv->len; j++)
00883             data[i++] = 0;
00884       }
00885 
00886       FreeTLV(tlv);
00887    } //end while
00888 
00889 
00890    command = MakeCommandC(CMD_GENERATE_AC, data, len);
00891    if(command == NULL) return NULL;
00892    command->cmdHeader->p1 = (uint8_t)acType;
00893    response = TerminalSendT0Command(command, convention, TC1, logger);
00894 
00895    FreeCAPDU(command);
00896    return response;
00897 }
00898 
00914 RAPDU* SignDynamicData(
00915         uint8_t convention,
00916         uint8_t TC1,
00917         const ByteArray *data,
00918         log_struct_t *logger)
00919 {
00920    CAPDU* command;
00921    RAPDU* response;
00922 
00923    command = MakeCommandC(CMD_INTERNAL_AUTHENTICATE, data->bytes, data->len);
00924    if(command == NULL) return NULL;
00925    response = TerminalSendT0Command(command, convention, TC1, logger);
00926    FreeCAPDU(command);
00927    return response;
00928 }
00929 
00950 uint8_t ParsePSD(RECORDList* rlist, const uint8_t *data, uint8_t lenData)
00951 {
00952    RECORD *rec, *adf;
00953    TLV *obj;
00954    uint8_t i;
00955 
00956    if(rlist == NULL) return RET_ERROR;
00957    rec = ParseRECORD(data, lenData);
00958    if(rec == NULL) return RET_ERROR;
00959 
00960    // parse each adf and put it in the list
00961    for(i = 0; i < rec->count; i++)
00962    {
00963       obj = rec->objects[i];
00964       adf = ParseManyTLV(obj->value, obj->len);
00965       if(adf == NULL || obj->tag1 != EMV_TAG1_APPLICATION_TEMPLATE || 
00966             obj->tag2 != EMV_TAG2_APPLICATION_TEMPLATE)
00967       {
00968          FreeRECORD(rec);
00969          return RET_ERROR;
00970       }
00971       
00972       rlist->count++;
00973       rlist->objects = (RECORD**)realloc(rlist->objects, rlist->count * sizeof(RECORD*));
00974       rlist->objects[rlist->count-1] = adf;
00975    }
00976 
00977    FreeRECORD(rec);
00978    return RET_SUCCESS;
00979 }
00980 
00993 APPINFO* ParseApplicationInfo(const uint8_t* data, uint8_t len)
00994 {
00995    APPINFO *appInfo = NULL;
00996    uint8_t i = 0, j, k, t, l, tag;
00997 
00998    if(data == NULL || len < 8) return NULL;
00999 
01000    tag = data[i++];   
01001    if(tag == 0x80) // remaining data is LEN | AIP | AFL
01002    {
01003       k = data[i++];
01004       if(k == EMV_EXTRA_LENGTH_BYTE) k = data[i++];
01005       if(len < k + 2) return NULL;
01006       j = (k - 2) / 4;
01007 
01008       appInfo = (APPINFO*)malloc(sizeof(APPINFO));
01009       if(appInfo == NULL) return NULL;
01010       appInfo->count = j;
01011       appInfo->aip[0] = data[i++];
01012       appInfo->aip[1] = data[i++];
01013       appInfo->aflList = (AFL**)malloc(j * sizeof(AFL*));
01014       if(appInfo->aflList == NULL)
01015       {
01016          free(appInfo);
01017          return NULL;
01018       }
01019 
01020       for(k = 0; k < j; k++)
01021       {
01022          appInfo->aflList[k] = (AFL*)malloc(sizeof(AFL));
01023          if(appInfo->aflList[k] == NULL)
01024          {
01025             FreeAPPINFO(appInfo);
01026             return NULL;
01027          }
01028          appInfo->aflList[k]->sfi = data[i++];
01029          appInfo->aflList[k]->recordStart = data[i++];
01030          appInfo->aflList[k]->recordEnd = data[i++];
01031          appInfo->aflList[k]->recordsOfflineAuth = data[i++];
01032       }
01033    } // end if t = 0x88
01034    else if(tag == 0x77) // constructed BER-TLV object
01035    {
01036       k = data[i++];
01037       j = 2;
01038       if(k == EMV_EXTRA_LENGTH_BYTE)
01039       {
01040          k = data[i++];
01041          j++;
01042       }
01043       if(len < k + j) return NULL;
01044 
01045       appInfo = (APPINFO*)malloc(sizeof(APPINFO));
01046       if(appInfo == NULL) return NULL;
01047       appInfo->count = 0;
01048       appInfo->aflList = NULL;
01049 
01050       while(i - j < k)
01051       {
01052          tag = data[i++];
01053          if(tag == 0x82)  // AIP
01054          {
01055             l = data[i++];
01056             if(l != 2)
01057             {
01058                FreeAPPINFO(appInfo);
01059                return NULL;
01060             }
01061             appInfo->aip[0] = data[i++];
01062             appInfo->aip[1] = data[i++];
01063          }
01064          else if(tag == 0x94) // AFL
01065          {
01066             l = data[i++];
01067             if(l == EMV_EXTRA_LENGTH_BYTE) l = data[i++];
01068             l = l / 4;
01069             appInfo->count = l;
01070             if(len > 0) appInfo->aflList = (AFL**)malloc(l * sizeof(AFL*));
01071             if(appInfo->aflList == NULL)
01072             {
01073                free(appInfo);
01074                return NULL;
01075             }
01076 
01077             for(t = 0; t < l; t++)
01078             {
01079                appInfo->aflList[t] = (AFL*)malloc(sizeof(AFL));
01080                if(appInfo->aflList[t] == NULL)
01081                {
01082                   FreeAPPINFO(appInfo);
01083                   return NULL;
01084                }
01085                appInfo->aflList[t]->sfi = data[i++];
01086                appInfo->aflList[t]->recordStart = data[i++];
01087                appInfo->aflList[t]->recordEnd = data[i++];
01088                appInfo->aflList[t]->recordsOfflineAuth = data[i++];
01089             }
01090          }
01091          else i++;
01092       }
01093 
01094    } // end else if t = 0x94
01095 
01096    return appInfo;
01097 }
01098 
01107 uint8_t GetSFIFromSELECT(const RAPDU *response)
01108 {
01109    uint8_t sfi = 0, i = 0;
01110 
01111    if(response == NULL || response->repData == NULL)
01112       return 0;
01113 
01114    while (i < response->lenData && response->repData[i] != 0x88) i++;
01115            
01116    if (i < response->lenData - 2) sfi = response->repData[i + 2];
01117                           
01118    return sfi;
01119 }
01120 
01129 TLV* GetPDOLFromFCI(const FCITemplate *fci)
01130 {
01131    uint8_t i;
01132    TLV *tmp;
01133 
01134    if(fci == NULL || fci->fciData == NULL || 
01135       fci->fciData->count == 0 || fci->fciData->objects == NULL)
01136          return NULL;
01137 
01138    for(i = 0; i < fci->fciData->count; i++)
01139    {
01140       tmp = fci->fciData->objects[i];
01141       if(tmp != NULL && tmp->tag1 == 0x9F && tmp->tag2 == 0x38)
01142          return tmp;
01143    }
01144 
01145    return NULL;
01146 }
01147 
01162 TLV* GetPDOL(const FCITemplate *fci)
01163 {
01164    TLV *pdol = NULL;
01165 
01166    if(fci != NULL) pdol = GetPDOLFromFCI(fci);
01167    if(pdol == NULL)
01168    {
01169       pdol = (TLV*)malloc(sizeof(TLV));
01170       if(pdol == NULL) return NULL;
01171       pdol->value = NULL;
01172       pdol->len = 0;
01173       pdol->tag1 = 0x9F;
01174       pdol->tag2 = 0x38;
01175    }
01176 
01177    return pdol;
01178 }
01179 
01194 ByteArray* GetDataObject(
01195         uint8_t convention,
01196         uint8_t TC1,
01197         CARD_PDO pdo,
01198         log_struct_t *logger)
01199 {
01200     ByteArray* data = NULL;
01201     CAPDU* command;
01202     RAPDU* response;
01203     TLV* tlv;
01204 
01205     command = MakeCommandC(CMD_GET_DATA, NULL, 0);
01206     if(command == NULL) return NULL;
01207     command->cmdHeader->p1 = 0x9F;
01208     command->cmdHeader->p2 = (uint8_t)pdo;
01209     response = TerminalSendT0Command(command, convention, TC1, logger);
01210     if(response == NULL)
01211     {
01212         FreeCAPDU(command);
01213         return NULL;
01214     }
01215     FreeCAPDU(command);
01216 
01217     if(response->repData == NULL)
01218     {
01219         FreeRAPDU(response);
01220         return NULL;
01221     }
01222 
01223     tlv = ParseTLV(response->repData, response->lenData, 1);
01224     FreeRAPDU(response);
01225     if(tlv == NULL) return NULL;
01226     data = (ByteArray*)malloc(sizeof(ByteArray));
01227     data->len = tlv->len;
01228     data->bytes = NULL;
01229     if(tlv->len > 0 && tlv->value != NULL)
01230     {
01231         data->bytes = (uint8_t*)malloc(data->len * sizeof(uint8_t));
01232         if(data->bytes == NULL)
01233         {
01234             free(data);
01235             return NULL;
01236         }
01237         memcpy(data->bytes, tlv->value, data->len);
01238     }
01239 
01240     return data;
01241 }
01242 
01253 FCITemplate* ParseFCI(const uint8_t *data, uint8_t lenData)
01254 {
01255    FCITemplate *fci;
01256    uint8_t i, len;
01257 
01258    if(data == NULL || lenData == 0)
01259       return NULL;
01260 
01261    i = 0;
01262    if(lenData < 4 || data[i++] != 0x6F) return NULL;
01263    len = data[i++];
01264    if(len == EMV_EXTRA_LENGTH_BYTE) len = data[i++];
01265    if(len > lenData - 2) return NULL;
01266 
01267    // get DF Name
01268    if(data[i++] != 0x84) return NULL;
01269    len = data[i++];
01270    if(len == EMV_EXTRA_LENGTH_BYTE) len = data[i++];
01271    if(len > lenData - 4) return NULL;
01272 
01273    fci = (FCITemplate*)malloc(sizeof(FCITemplate));
01274    if(fci == NULL) return NULL;
01275    fci->dfName = (uint8_t*)malloc(len * sizeof(uint8_t));
01276    if(fci->dfName == NULL)
01277    {
01278       free(fci);
01279       return NULL;
01280    }
01281    memcpy(fci->dfName, &data[i], len);
01282    fci->lenDFName = len;
01283    i += len;
01284 
01285    // get FCI Proprietary template (sfi, app label, etc...)
01286    if(data[i++] != 0xA5)
01287    {
01288       FreeFCITemplate(fci);
01289       return NULL;
01290    }
01291    len = data[i++];
01292    if(len == EMV_EXTRA_LENGTH_BYTE) len = data[i++];
01293    if(len > (lenData - fci->lenDFName))
01294    {
01295       FreeFCITemplate(fci);
01296       return NULL;
01297    }
01298    fci->fciData = ParseManyTLV(&data[i], len);
01299    if(fci->fciData == NULL)
01300    {
01301       FreeFCITemplate(fci);
01302       return NULL;
01303    }
01304 
01305    return fci;
01306 }
01307 
01321 TLV* ParseTLV(const uint8_t *data, uint8_t lenData, uint8_t includeValue)
01322 {       
01323    TLV* obj = NULL;
01324    uint8_t i = 0, j;
01325 
01326    obj = (TLV*)malloc(sizeof(TLV));
01327    if(obj == NULL) return NULL;
01328    obj->value = NULL;
01329 
01330    obj->tag1 = data[i++];
01331    if((obj->tag1 & 0x1F) == 0x1F)
01332           obj->tag2 = data[i++];
01333    else
01334           obj->tag2 = 0;
01335 
01336    obj->len = data[i++];
01337    if(obj->len == EMV_EXTRA_LENGTH_BYTE) obj->len = data[i++];  // for len > 127
01338 
01339    if(includeValue != 0)
01340    {
01341       if(obj->len > lenData - 2)
01342       {
01343          free(obj);
01344          return NULL;
01345       }
01346 
01347       obj->value = (uint8_t*)malloc(obj->len*sizeof(uint8_t));
01348       if(obj->value == NULL)
01349       {
01350             free(obj);              
01351             return NULL;
01352       }
01353 
01354       for(j = 0; j < obj->len; j++)
01355             obj->value[j] = data[i++];
01356    }
01357 
01358    return obj;
01359 }
01360 
01369 TLV* CopyTLV(const TLV *data)
01370 {
01371    TLV *clone;
01372 
01373    if(data == NULL) return NULL;
01374 
01375    clone = (TLV*)malloc(sizeof(TLV));
01376    if(clone == NULL) return NULL;
01377    clone->len = 0;
01378    clone->tag1 = data->tag1;
01379    clone->tag2 = data->tag2;
01380    clone->value = NULL;
01381 
01382    if(data->value != NULL && (data->len > 0))
01383    {
01384       clone->value = (uint8_t*)malloc(data->len * sizeof(uint8_t));
01385       if(clone->value == NULL)
01386       {
01387          free(clone);
01388          return NULL;
01389       }
01390       memcpy(clone->value, data->value, data->len);
01391       clone->len = data->len;
01392    }
01393 
01394    return clone;
01395 }
01396 
01409 RECORD* ParseRECORD(const uint8_t *data, uint8_t lenData)
01410 {
01411    uint8_t i, len;
01412 
01413    if(data == NULL || lenData == 0)
01414       return NULL;
01415 
01416    i = 0;
01417    if(lenData < 4 || data[i++] != 0x70) return NULL;
01418    len = data[i++];
01419    if(len == EMV_EXTRA_LENGTH_BYTE) len = data[i++];
01420    if(len > lenData - 2) return NULL;
01421 
01422    return ParseManyTLV(&data[i], len);
01423 }
01424 
01439 uint8_t AddRECORD(RECORD *dest, const RECORD *src)
01440 {
01441    uint8_t i, k;
01442 
01443    if(dest == NULL || src == NULL || src->objects == NULL) return RET_ERROR;
01444 
01445    k = dest->count + src->count;
01446    dest->objects = (TLV**)realloc(dest->objects, k * sizeof(TLV*));
01447    if(dest->objects == NULL)
01448       return RET_ERROR;
01449 
01450    for(i = 0; i < src->count; i++)
01451    {
01452       dest->objects[dest->count] = CopyTLV(src->objects[i]);
01453       if(dest->objects[dest->count] == NULL) return RET_ERROR;
01454       dest->count++;
01455    }
01456 
01457    return 0;
01458 }
01459 
01472 TLV* GetTLVFromRECORD(RECORD *rec, uint8_t tag1, uint8_t tag2)
01473 {
01474    TLV *tlv;
01475    uint8_t i;
01476 
01477    if(rec == NULL) return NULL;
01478    for(i = 0; i < rec->count; i++)
01479    {
01480       tlv = rec->objects[i];
01481       if(tlv != NULL && tlv->tag1 == tag1 && tlv->tag2 == tag2)
01482          return tlv;
01483    }
01484 
01485    return NULL;
01486 }
01487 
01499 RECORD* ParseManyTLV(const uint8_t *data, uint8_t lenData)
01500 {
01501    RECORD *rec;
01502    TLV *obj;
01503    uint8_t i;
01504 
01505    if(data == NULL || lenData == 0)
01506       return NULL;
01507 
01508    rec = (RECORD*)malloc(sizeof(RECORD));
01509    if(rec == NULL) return NULL;
01510    rec->count = 0;
01511    rec->objects = NULL;
01512    i = 0;
01513 
01514    while(i < lenData)
01515    {
01516       obj = ParseTLV(&(data[i]), lenData - i, 1);
01517       if(obj == NULL)
01518       {
01519         FreeRECORD(rec);
01520         return NULL;
01521       }
01522       i += 2 + obj->len;
01523       if(obj->tag2 != 0) i++;
01524       if(obj->len > 127) i++;
01525 
01526       rec->count++;
01527       rec->objects = (TLV**)realloc(rec->objects, rec->count * sizeof(TLV*));
01528       rec->objects[rec->count-1] = obj;
01529    }
01530 
01531    return rec;
01532 }
01533 
01534 
01546 uint8_t AmountPositionInCDOLRecord(const RECORD *record)
01547 {
01548    uint8_t i;
01549    TLV *cdol1 = NULL, *obj;
01550 
01551    if(record == NULL) return 0;
01552 
01553    for(i = 0; i < record->count; i++)
01554           if(record->objects[i] != NULL && record->objects[i]->tag1 == 0x8C)
01555           {
01556                   cdol1 = record->objects[i];
01557                   break;
01558           }
01559 
01560    if(cdol1 == NULL) return 0;
01561 
01562    i = 0;
01563    while(i < cdol1->len)
01564    {
01565           obj = ParseTLV(&(cdol1->value[i]), cdol1->len - i, 0);
01566           if(obj == NULL) return 0;
01567 
01568           if(obj->tag1 == 0x9F && obj->tag2 == 0x02)
01569           {
01570                   free(obj);
01571                   return i + 1;
01572           }
01573 
01574           i += 2;
01575           if(obj->tag2 != 0) i++;
01576 
01577           free(obj);
01578    }
01579 
01580    return 0;
01581 }
01582 
01592 ByteArray* SerializeTLV(const TLV* tlv)
01593 {
01594    ByteArray *stream;
01595    uint8_t *data;
01596    uint8_t len, i;
01597 
01598    if(tlv == NULL) return NULL;
01599 
01600    len = 1; // first tag
01601    if(tlv->tag2 != 0) len++;
01602    len++; // first len byte
01603    if(tlv->len > 127) len++;
01604    if(tlv->value != NULL) len += tlv->len;
01605    data = (uint8_t*)malloc(len * sizeof(uint8_t));
01606    if(data == NULL) return NULL;
01607 
01608    i = 0;
01609    data[i++] = tlv->tag1;
01610    if(tlv->tag2 != 0) data[i++] = tlv->tag2;
01611    if(tlv->len > 127) data[i++] = EMV_EXTRA_LENGTH_BYTE;
01612    data[i++] = tlv->len;
01613    if(tlv->value != NULL && tlv->len != 0)
01614       memcpy(&data[i], tlv->value, tlv->len);
01615 
01616    stream = MakeByteArray(data, len);
01617    if(stream == NULL)
01618    {
01619       free(data);
01620       return NULL;
01621    }
01622 
01623    return stream;
01624 }
01625 
01631 void FreeTLV(TLV *data)
01632 {
01633    if(data == NULL) return;
01634 
01635    if(data->value != NULL)
01636    {
01637       free(data->value);
01638       data->value = NULL;
01639    }
01640    free(data);
01641 }
01642 
01648 void FreeRECORD(RECORD *data)
01649 {
01650    uint8_t i;
01651 
01652    if(data == NULL) return;
01653 
01654    if(data->objects != NULL)
01655    {
01656       for(i = 0; i < data->count; i++)
01657          if(data->objects[i] != NULL)
01658          {
01659             FreeTLV(data->objects[i]);
01660             data->objects[i] = NULL;
01661          }
01662       free(data->objects);
01663       data->objects = NULL;
01664    }
01665    free(data);
01666 }
01667 
01673 void FreeRECORDList(RECORDList *data)
01674 {
01675    uint8_t i = 0;
01676 
01677    if(data->objects != NULL)
01678    {
01679       for(i = 0; i < data->count; i++)
01680          if(data->objects[i] != NULL)
01681          {
01682             FreeRECORD(data->objects[i]);
01683             data->objects[i] = NULL;
01684          }
01685       free(data->objects);
01686       data->objects = NULL;
01687    }
01688    free(data);
01689 }
01690 
01696 void FreeFCITemplate(FCITemplate *data)
01697 {
01698    if(data->fciData != NULL)
01699    {
01700       FreeRECORD(data->fciData);
01701       data->fciData = NULL;
01702    }
01703    if(data->dfName != NULL)
01704    {
01705       free(data->dfName);
01706       data->dfName = NULL;
01707    }
01708    free(data);
01709 }
01710 
01716 void FreeFCIList(FCIList *data)
01717 {
01718    uint8_t i = 0;
01719 
01720    if(data->objects != NULL)
01721    {
01722       for(i = 0; i < data->count; i++)
01723          if(data->objects[i] != NULL)
01724          {
01725             FreeFCITemplate(data->objects[i]);
01726             data->objects[i] = NULL;
01727          }
01728       free(data->objects);
01729       data->objects = NULL;
01730    }
01731    free(data);
01732 }
01733 
01739 void FreeAPPINFO(APPINFO *data)
01740 {
01741    uint8_t i;
01742 
01743    if(data == NULL) return;
01744 
01745    if(data->aflList != NULL)
01746    {
01747       for(i = 0; i < data->count; i++)
01748          if(data->aflList[i] != NULL)
01749          {
01750             free(data->aflList[i]);
01751             data->aflList[i] = NULL;
01752          }
01753       free(data->aflList);
01754       data->aflList = NULL;
01755    }
01756    free(data);
01757 }
01758 
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Defines