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
00051 static RAPDU* TerminalSendT0CommandR(CAPDU* tmpCommand, RAPDU *tmpResponse,
00052 uint8_t inverse_convention, uint8_t TC1, log_struct_t *logger);
00053
00054
00055
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,
00063 0xA0, 0, 0, 0, 0x03, 0x10, 0x10,
00064 0xA0, 0, 0, 0, 0x04, 0x10, 0x10,
00065 0xA0, 0, 0, 0, 0x03, 0x80, 0x02,
00066 0xA0, 0, 0, 0, 0x04, 0x80, 0x02,
00067 0xA0, 0, 0, 0x02, 0x44, 0, 0x10
00068 };
00069
00070
00071
00072
00073
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
00135 JTAG_P1_Low();
00136 JTAG_P3_Low();
00137 #endif
00138
00139 LoopICCETU(16);
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
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
00181
00182
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
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
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
00410 if(offlineAuthData != NULL &&
00411 (afl->recordsOfflineAuth > j - afl->recordStart))
00412 {
00413 if(afl->sfi > 0x50)
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;
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 }
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 }
00453 }
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
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
00632
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
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
00881 {
00882 for(j = 0; j < tlv->len; j++)
00883 data[i++] = 0;
00884 }
00885
00886 FreeTLV(tlv);
00887 }
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
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)
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 }
01034 else if(tag == 0x77)
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)
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)
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 }
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
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
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++];
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;
01601 if(tlv->tag2 != 0) len++;
01602 len++;
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