00001
00024 #include <string.h>
00025 #include <util/delay.h>
00026 #include <stdlib.h>
00027
00028 #include "EMV.h"
00029 #include "halSCD.h"
00030 #include "terminal.h"
00031 #include "emv_values.h"
00032 #include "scd_values.h"
00033
00035 #define DEBUG 0
00036
00037
00038
00039 static RAPDU* TerminalSendT0CommandR(CAPDU* tmpCommand, RAPDU *tmpResponse,
00040 uint8_t inverse_convention, uint8_t TC1);
00041
00042
00043
00044 static const uint8_t nPSELen = 14;
00045 static const uint8_t bPSEString[14] = { '1', 'P', 'A', 'Y', '.', 'S', 'Y',
00046 'S', '.', 'D', 'D', 'F', '0', '1'};
00047 static const uint8_t nAIDLen = 7;
00048 static const uint8_t nAIDEntries = 6;
00049 static const uint8_t bAIDList[42] = {
00050 0xA0, 0, 0, 0, 0x03, 0x10, 0x10,
00051 0xA0, 0, 0, 0, 0x04, 0x10, 0x10,
00052 0xA0, 0, 0, 0, 0x29, 0x10, 0x10,
00053 0xA0, 0, 0, 0, 0x03, 0x80, 0x02,
00054 0xA0, 0, 0, 0, 0x04, 0x80, 0x02,
00055 0xA0, 0, 0, 0x02, 0x44, 0, 0x10
00056 };
00057
00058
00059
00060
00061
00062
00063
00079 RAPDU* TerminalSendT0Command(CAPDU* cmd, uint8_t inverse_convention,
00080 uint8_t TC1)
00081 {
00082 CAPDU *tmpCommand;
00083
00084 tmpCommand = CopyCAPDU(cmd);
00085 if(tmpCommand == NULL) return NULL;
00086
00087 return TerminalSendT0CommandR(tmpCommand, NULL, inverse_convention, TC1);
00088 }
00089
00090
00106 static RAPDU* TerminalSendT0CommandR(CAPDU *tmpCommand, RAPDU *tmpResponse,
00107 uint8_t inverse_convention, uint8_t TC1)
00108 {
00109 RAPDU *response, *tmp;
00110
00111 LoopICCETU(16);
00112
00113 if(SendT0Command(inverse_convention, TC1, tmpCommand))
00114 {
00115 FreeRAPDU(tmpResponse);
00116 FreeCAPDU(tmpCommand);
00117 return NULL;
00118 }
00119 tmp = ReceiveT0Response(inverse_convention, tmpCommand->cmdHeader);
00120 if(tmp == NULL || tmp->repStatus == NULL)
00121 {
00122 FreeRAPDU(tmpResponse);
00123 FreeCAPDU(tmpCommand);
00124 return NULL;
00125 }
00126
00127 response = CopyRAPDU(tmp);
00128 if(response == NULL)
00129 {
00130 FreeRAPDU(tmpResponse);
00131 FreeRAPDU(tmp);
00132 FreeCAPDU(tmpCommand);
00133 return NULL;
00134 }
00135
00136
00137
00138
00139 if(tmpResponse != NULL && tmpResponse->repData != NULL &&
00140 tmpResponse->lenData != 0)
00141 {
00142 response->lenData = tmpResponse->lenData + tmp->lenData;
00143 response->repData = (uint8_t*)realloc(response->repData,
00144 (response->lenData) * sizeof(uint8_t));
00145 if(response->repData == NULL)
00146 {
00147 FreeRAPDU(tmpResponse);
00148 FreeRAPDU(tmp);
00149 FreeRAPDU(response);
00150 FreeCAPDU(tmpCommand);
00151 return NULL;
00152 }
00153 memcpy(response->repData, tmpResponse->repData, tmpResponse->lenData);
00154 memcpy(&(response->repData[tmpResponse->lenData]), tmp->repData, tmp->lenData);
00155 }
00156 FreeRAPDU(tmp);
00157 FreeRAPDU(tmpResponse);
00158
00159 if(response->repStatus->sw1 == (uint8_t)SW1_MORE_DATA ||
00160 response->repStatus->sw1 == (uint8_t)SW1_WARNING1 ||
00161 response->repStatus->sw1 == (uint8_t)SW1_WARNING2)
00162 {
00163 FreeCAPDU(tmpCommand);
00164 CAPDU *cmdGet = MakeCommandC(CMD_GET_RESPONSE, NULL, 0);
00165 if(cmdGet == NULL)
00166 {
00167 FreeRAPDU(response);
00168 return NULL;
00169 }
00170
00171 if(response->repStatus->sw1 == (uint8_t)SW1_MORE_DATA)
00172 cmdGet->cmdHeader->p3 = response->repStatus->sw2;
00173
00174 return TerminalSendT0CommandR(cmdGet, response, inverse_convention, TC1);
00175 }
00176 else if(response->repStatus->sw1 == (uint8_t)SW1_WRONG_LENGTH)
00177 {
00178 tmpCommand->cmdHeader->p3 = response->repStatus->sw2;
00179 return TerminalSendT0CommandR(tmpCommand, response, inverse_convention, TC1);
00180 }
00181
00182
00183 FreeCAPDU(tmpCommand);
00184 return response;
00185 }
00186
00198 FCITemplate* ApplicationSelection(uint8_t convention, uint8_t TC1)
00199 {
00200 CAPDU* command;
00201 RAPDU* response;
00202 uint8_t sfi;
00203
00204
00205 command = MakeCommandC(CMD_SELECT, bPSEString, nPSELen);
00206 if(command == NULL) return NULL;
00207 response = TerminalSendT0Command(command, convention, TC1);
00208 FreeCAPDU(command);
00209 if(response == NULL) return NULL;
00210
00211 if(response->repStatus->sw1 == 0x90 &&
00212 response->repStatus->sw2 == 0)
00213 {
00214 sfi = GetSFIFromSELECT(response);
00215 FreeRAPDU(response);
00216 return SelectFromPSE(convention, TC1, sfi);
00217 }
00218 else if((response->repStatus->sw1 == 0x6A && response->repStatus->sw2 == 0x82) ||
00219 (response->repStatus->sw1 == 0x62 && response->repStatus->sw2 == 0x83))
00220 {
00221 FreeRAPDU(response);
00222 return SelectFromAID(convention, TC1);
00223 }
00224
00225 FreeRAPDU(response);
00226 return NULL;
00227 }
00228
00241 APPINFO* InitializeTransaction(uint8_t convention, uint8_t TC1,
00242 const FCITemplate *fci)
00243 {
00244 TLV *pdol;
00245 ByteArray *data;
00246 CAPDU *command;
00247 RAPDU *response;
00248 APPINFO *appInfo;
00249
00250 pdol = GetPDOL(fci);
00251 if(pdol == NULL) return NULL;
00252 pdol->tag1 = 0x83;
00253 pdol->tag2 = 0;
00254 data = SerializeTLV(pdol);
00255 if(data == NULL) return NULL;
00256
00257 command = MakeCommandC(CMD_GET_PROCESSING_OPTS, data->bytes, data->len);
00258 FreeByteArray(data);
00259 if(command == NULL) return NULL;
00260 response = TerminalSendT0Command(command, convention, TC1);
00261 FreeCAPDU(command);
00262 if(response == NULL) return NULL;
00263
00264 appInfo = ParseApplicationInfo(response->repData, response->lenData);
00265 FreeRAPDU(response);
00266
00267 return appInfo;
00268 }
00269
00285 RECORD* GetTransactionData(uint8_t convention, uint8_t TC1, const APPINFO* appInfo,
00286 ByteArray *offlineAuthData)
00287 {
00288 RECORD *data, *tmp;
00289 CAPDU *command;
00290 RAPDU *response;
00291 AFL* afl;
00292 uint8_t i, j, k, l;
00293
00294 if(appInfo == NULL || appInfo->aflList == NULL) return NULL;
00295 data = (RECORD*)malloc(sizeof(RECORD));
00296 data->count = 0;
00297 data->objects = NULL;
00298
00299 if(offlineAuthData != NULL)
00300 {
00301 offlineAuthData->len = 0;
00302 offlineAuthData->bytes = NULL;
00303 }
00304
00305 command = MakeCommandC(CMD_READ_RECORD, NULL, 0);
00306 if(command == NULL)
00307 {
00308 free(data);
00309 return NULL;
00310 }
00311
00312 for(i = 0; i < appInfo->count; i++)
00313 {
00314 afl = appInfo->aflList[i];
00315 if(afl == NULL) continue;
00316
00317 for(j = afl->recordStart; j <= afl->recordEnd; j++)
00318 {
00319 command->cmdHeader->p1 = j;
00320 command->cmdHeader->p2 = (uint8_t)(afl->sfi | 4);
00321 response = TerminalSendT0Command(command, convention, TC1);
00322
00323 if(response == NULL || response->repStatus->sw1 != 0x90 ||
00324 response->repStatus->sw2 != 0)
00325 {
00326 if(response != NULL) FreeRAPDU(response);
00327 FreeRECORD(data);
00328 FreeCAPDU(command);
00329 return NULL;
00330 }
00331 if(response->repData == NULL || response->lenData < 2)
00332 continue;
00333
00334
00335 if(offlineAuthData != NULL &&
00336 (afl->recordsOfflineAuth > j - afl->recordStart))
00337 {
00338 if(afl->sfi > 0x50)
00339 {
00340 k = response->lenData + offlineAuthData->len;
00341 offlineAuthData->bytes =
00342 (uint8_t*)realloc(offlineAuthData->bytes, k);
00343 if(offlineAuthData->bytes != NULL)
00344 {
00345 memcpy(&offlineAuthData->bytes[offlineAuthData->len],
00346 response->repData, response->lenData);
00347 offlineAuthData->len = k;
00348 }
00349 else offlineAuthData->len = 0;
00350 }
00351 else
00352 {
00353 l = 2;
00354 if(response->repData[1] == EMV_EXTRA_LENGTH_BYTE) l++;
00355 k = response->lenData - l + offlineAuthData->len;
00356 offlineAuthData->bytes = (uint8_t*)realloc(offlineAuthData->bytes, k);
00357 if(offlineAuthData->bytes != NULL)
00358 {
00359 memcpy(&offlineAuthData->bytes[offlineAuthData->len],
00360 &response->repData[l], response->lenData - l);
00361 offlineAuthData->len += response->lenData - l;
00362 }
00363 else offlineAuthData->len = 0;
00364
00365 }
00366 }
00367
00368 tmp = ParseRECORD(response->repData, response->lenData);
00369 FreeRAPDU(response);
00370 if(AddRECORD(data, tmp))
00371 {
00372 FreeRECORD(data);
00373 FreeCAPDU(command);
00374 return NULL;
00375 }
00376 FreeRECORD(tmp);
00377 }
00378 }
00379
00380 FreeCAPDU(command);
00381 return data;
00382 }
00383
00384
00399 FCITemplate* SelectFromAID(uint8_t convention, uint8_t TC1)
00400 {
00401 CAPDU* command;
00402 RAPDU* response;
00403 volatile uint8_t i = 0;
00404 FCITemplate* fci = NULL;
00405
00406 while(i < nAIDEntries)
00407 {
00408 command = MakeCommandC(CMD_SELECT, &(bAIDList[nAIDLen * i]), nAIDLen);
00409 if(command == NULL) return NULL;
00410 response = TerminalSendT0Command(command, convention, TC1);
00411 FreeCAPDU(command);
00412 if(response == NULL) return NULL;
00413
00414 if(response->repStatus->sw1 == 0x90 && response->repStatus->sw2 == 0)
00415 {
00416 fci = ParseFCI(response->repData, response->lenData);
00417 FreeRAPDU(response);
00418 return fci;
00419 }
00420 else if((response->repStatus->sw1 != 0x6A || response->repStatus->sw2 != 0x82) &&
00421 (response->repStatus->sw1 != 0x62 || response->repStatus->sw2 != 0x83))
00422 {
00423 FreeRAPDU(response);
00424 return NULL;
00425 }
00426
00427 FreeRAPDU(response);
00428 i++;
00429 }
00430
00431 return NULL;
00432 }
00433
00446 FCITemplate* SelectFromPSE(uint8_t convention, uint8_t TC1,
00447 uint8_t sfiPSE)
00448 {
00449 FCITemplate* fci = NULL;
00450 CAPDU* command = NULL;
00451 RAPDU* response = NULL;
00452 RECORDList* rlist = NULL;
00453 TLV* adfName = NULL;
00454 uint8_t more, status;
00455
00456
00457 rlist = (RECORDList*)malloc(sizeof(RECORDList));
00458 if(rlist == NULL) goto clean;
00459 rlist->count = 0;
00460 rlist->objects = NULL;
00461 command = MakeCommandC(CMD_READ_RECORD, NULL, 0);
00462 if(command == NULL) goto clean;
00463 command->cmdHeader->p1 = 0;
00464 command->cmdHeader->p2 = (uint8_t)((sfiPSE << 3) | 4);
00465 more = 1;
00466
00467 while(more)
00468 {
00469 more = 0;
00470 command->cmdHeader->p1 += 1;
00471 response = TerminalSendT0Command(command, convention, TC1);
00472
00473 if(response == NULL) goto clean;
00474 if(response->repData != NULL)
00475 {
00476 more = 1;
00477 status = ParsePSD(rlist, response->repData, response->lenData);
00478 if(status) goto clean;
00479 }
00480 FreeRAPDU(response);
00481 if(rlist == NULL) goto clean;
00482 }
00483 FreeCAPDU(command);
00484 command = NULL;
00485
00486
00487
00488 adfName = rlist->objects[0]->objects[0];
00489 command = MakeCommandC(CMD_SELECT, adfName->value, adfName->len);
00490 if(command == NULL) goto clean;
00491 response = TerminalSendT0Command(command, convention, TC1);
00492 FreeCAPDU(command);
00493 command = NULL;
00494 if(response == NULL) goto clean;
00495 if(response->repData != NULL && response->repStatus->sw1 == SW1_COMPLETED)
00496 fci = ParseFCI(response->repData, response->lenData);
00497 FreeRAPDU(response);
00498
00499 clean:
00500 if(command != NULL)
00501 FreeCAPDU(command);
00502 if(rlist != NULL)
00503 FreeRECORDList(rlist);
00504
00505 return fci;
00506 }
00507
00520 uint8_t VerifyPlaintextPIN(uint8_t convention, uint8_t TC1,
00521 const ByteArray *pin)
00522 {
00523 CAPDU* command;
00524 RAPDU* response;
00525
00526 if(pin == NULL || pin->len == 0) return -1;
00527
00528 command = MakeCommandC(CMD_VERIFY, pin->bytes, pin->len);
00529 if(command == NULL) return RET_ERROR;
00530 response = TerminalSendT0Command(command, convention, TC1);
00531 FreeCAPDU(command);
00532 if(response == NULL) return RET_ERROR;
00533 if(response->repStatus == NULL || response->repStatus->sw1 != 0x90 ||
00534 response->repStatus->sw2 != 0)
00535 {
00536 FreeRAPDU(response);
00537 return RET_ERROR;
00538 }
00539
00540 FreeRAPDU(response);
00541 return 0;
00542 }
00543
00562 RAPDU* SendGenerateAC(uint8_t convention, uint8_t TC1, AC_REQ_TYPE acType,
00563 const TLV* cdol, const GENERATE_AC_PARAMS *params)
00564 {
00565 CAPDU* command;
00566 RAPDU* response;
00567 uint8_t* data;
00568 uint8_t i, j, k, len;
00569 TLV* tlv;
00570
00571 if(cdol == NULL || params == NULL) return NULL;
00572
00573
00574 data = NULL;
00575 len = 0;
00576 i = 0;
00577 k = 0;
00578 while(k < cdol->len)
00579 {
00580 tlv = ParseTLV(&(cdol->value[k]), cdol->len - k, 0);
00581 k += 2;
00582 if(tlv == NULL) continue;
00583 if(tlv->tag2 != 0) k += 1;
00584 len += tlv->len;
00585 data = (uint8_t*)realloc(data, len * sizeof(uint8_t));
00586 if(data == NULL)
00587 {
00588 FreeTLV(tlv);
00589 return NULL;
00590 }
00591
00592 if(tlv->tag1 == 0x9F && tlv->tag2 == 0x02)
00593 {
00594 for(j = 0; j < tlv->len && j < sizeof(params->amount); j++)
00595 data[i++] = params->amount[j];
00596 while(j < tlv->len)
00597 {
00598 data[i++] = 0;
00599 j++;
00600 }
00601 }
00602 else if(tlv->tag1 == 0x9F && tlv->tag2 == 0x03)
00603 {
00604 for(j = 0; j < tlv->len && j < sizeof(params->amountOther); j++)
00605 data[i++] = params->amountOther[j];
00606 while(j < tlv->len)
00607 {
00608 data[i++] = 0;
00609 j++;
00610 }
00611 }
00612 else if(tlv->tag1 == 0x9F && tlv->tag2 == 0x1A)
00613 {
00614 for(j = 0; j < tlv->len && j < sizeof(params->terminalCountryCode); j++)
00615 data[i++] = params->terminalCountryCode[j];
00616 while(j < tlv->len)
00617 {
00618 data[i++] = 0;
00619 j++;
00620 }
00621 }
00622 else if(tlv->tag1 == 0x95)
00623 {
00624 for(j = 0; j < tlv->len && j < sizeof(params->tvr); j++)
00625 data[i++] = params->tvr[j];
00626 while(j < tlv->len)
00627 {
00628 data[i++] = 0;
00629 j++;
00630 }
00631 }
00632 else if(tlv->tag1 == 0x5F && tlv->tag2 == 0x2A)
00633 {
00634 for(j = 0; j < tlv->len && j < sizeof(params->terminalCurrencyCode); j++)
00635 data[i++] = params->terminalCurrencyCode[j];
00636 while(j < tlv->len)
00637 {
00638 data[i++] = 0;
00639 j++;
00640 }
00641 }
00642 else if(tlv->tag1 == 0x9A)
00643 {
00644 for(j = 0; j < tlv->len && j < sizeof(params->transactionDate); j++)
00645 data[i++] = params->transactionDate[j];
00646 while(j < tlv->len)
00647 {
00648 data[i++] = 0;
00649 j++;
00650 }
00651 }
00652 else if(tlv->tag1 == 0x9C)
00653 {
00654 data[i++] = params->transactionType;
00655 }
00656 else if(tlv->tag1 == 0x9F && tlv->tag2 == 0x37)
00657 {
00658 for(j = 0; j < tlv->len && j < sizeof(params->unpredictableNumber); j++)
00659 data[i++] = params->unpredictableNumber[j];
00660 while(j < tlv->len)
00661 {
00662 data[i++] = 0;
00663 j++;
00664 }
00665 }
00666 else if(tlv->tag1 == 0x9F && tlv->tag2 == 0x35)
00667 {
00668 data[i++] = params->terminalType;
00669 }
00670 else if(tlv->tag1 == 0x9F && tlv->tag2 == 0x45)
00671 {
00672 for(j = 0; j < tlv->len && j < sizeof(params->dataAuthCode); j++)
00673 data[i++] = params->dataAuthCode[j];
00674 while(j < tlv->len)
00675 {
00676 data[i++] = 0;
00677 j++;
00678 }
00679 }
00680 else if(tlv->tag1 == 0x9F && tlv->tag2 == 0x4C)
00681 {
00682 for(j = 0; j < tlv->len && j < sizeof(params->iccDynamicNumber); j++)
00683 data[i++] = params->iccDynamicNumber[j];
00684 while(j < tlv->len)
00685 {
00686 data[i++] = 0;
00687 j++;
00688 }
00689 }
00690 else if(tlv->tag1 == 0x9F && tlv->tag2 == 0x34)
00691 {
00692 for(j = 0; j < tlv->len && j < sizeof(params->cvmResults); j++)
00693 data[i++] = params->cvmResults[j];
00694 while(j < tlv->len)
00695 {
00696 data[i++] = 0;
00697 j++;
00698 }
00699 }
00700 else
00701 {
00702 for(j = 0; j < tlv->len; j++)
00703 data[i++] = 0;
00704 }
00705
00706 FreeTLV(tlv);
00707 }
00708
00709
00710 command = MakeCommandC(CMD_GENERATE_AC, data, len);
00711 if(command == NULL) return NULL;
00712 command->cmdHeader->p1 = (uint8_t)acType;
00713 response = TerminalSendT0Command(command, convention, TC1);
00714 FreeCAPDU(command);
00715 return response;
00716 }
00717
00732 RAPDU* SignDynamicData(uint8_t convention, uint8_t TC1, const ByteArray *data)
00733 {
00734 CAPDU* command;
00735 RAPDU* response;
00736
00737 command = MakeCommandC(CMD_INTERNAL_AUTHENTICATE, data->bytes, data->len);
00738 if(command == NULL) return NULL;
00739 response = TerminalSendT0Command(command, convention, TC1);
00740 FreeCAPDU(command);
00741 return response;
00742 }
00743
00764 uint8_t ParsePSD(RECORDList* rlist, const uint8_t *data, uint8_t lenData)
00765 {
00766 RECORD *rec, *adf;
00767 TLV *obj;
00768 uint8_t i;
00769
00770 if(rlist == NULL) return RET_ERROR;
00771 rec = ParseRECORD(data, lenData);
00772 if(rec == NULL) return RET_ERROR;
00773
00774
00775 for(i = 0; i < rec->count; i++)
00776 {
00777 obj = rec->objects[i];
00778 adf = ParseManyTLV(obj->value, obj->len);
00779 if(adf == NULL || obj->tag1 != EMV_TAG1_APPLICATION_TEMPLATE ||
00780 obj->tag2 != EMV_TAG2_APPLICATION_TEMPLATE)
00781 {
00782 FreeRECORD(rec);
00783 return RET_ERROR;
00784 }
00785
00786 rlist->count++;
00787 rlist->objects = (RECORD**)realloc(rlist->objects, rlist->count * sizeof(RECORD*));
00788 rlist->objects[rlist->count-1] = adf;
00789 }
00790
00791 FreeRECORD(rec);
00792 return RET_SUCCESS;
00793 }
00794
00807 APPINFO* ParseApplicationInfo(const uint8_t* data, uint8_t len)
00808 {
00809 APPINFO *appInfo = NULL;
00810 uint8_t i = 0, j, k, t, l, tag;
00811
00812 if(data == NULL || len < 8) return NULL;
00813
00814 tag = data[i++];
00815 if(tag == 0x80)
00816 {
00817 k = data[i++];
00818 if(k == EMV_EXTRA_LENGTH_BYTE) k = data[i++];
00819 if(len < k + 2) return NULL;
00820 j = (k - 2) / 4;
00821
00822 appInfo = (APPINFO*)malloc(sizeof(APPINFO));
00823 if(appInfo == NULL) return NULL;
00824 appInfo->count = j;
00825 appInfo->aip[0] = data[i++];
00826 appInfo->aip[1] = data[i++];
00827 appInfo->aflList = (AFL**)malloc(j * sizeof(AFL*));
00828 if(appInfo->aflList == NULL)
00829 {
00830 free(appInfo);
00831 return NULL;
00832 }
00833
00834 for(k = 0; k < j; k++)
00835 {
00836 appInfo->aflList[k] = (AFL*)malloc(sizeof(AFL));
00837 if(appInfo->aflList[k] == NULL)
00838 {
00839 FreeAPPINFO(appInfo);
00840 return NULL;
00841 }
00842 appInfo->aflList[k]->sfi = data[i++];
00843 appInfo->aflList[k]->recordStart = data[i++];
00844 appInfo->aflList[k]->recordEnd = data[i++];
00845 appInfo->aflList[k]->recordsOfflineAuth = data[i++];
00846 }
00847 }
00848 else if(tag == 0x77)
00849 {
00850 k = data[i++];
00851 j = 2;
00852 if(k == EMV_EXTRA_LENGTH_BYTE)
00853 {
00854 k = data[i++];
00855 j++;
00856 }
00857 if(len < k + j) return NULL;
00858
00859 appInfo = (APPINFO*)malloc(sizeof(APPINFO));
00860 if(appInfo == NULL) return NULL;
00861 appInfo->count = 0;
00862 appInfo->aflList = NULL;
00863
00864 while(i - j < k)
00865 {
00866 tag = data[i++];
00867 if(tag == 0x82)
00868 {
00869 l = data[i++];
00870 if(l != 2)
00871 {
00872 FreeAPPINFO(appInfo);
00873 return NULL;
00874 }
00875 appInfo->aip[0] = data[i++];
00876 appInfo->aip[1] = data[i++];
00877 }
00878 else if(tag == 0x94)
00879 {
00880 l = data[i++];
00881 if(l == EMV_EXTRA_LENGTH_BYTE) l = data[i++];
00882 l = l / 4;
00883 appInfo->count = l;
00884 if(len > 0) appInfo->aflList = (AFL**)malloc(l * sizeof(AFL*));
00885 if(appInfo->aflList == NULL)
00886 {
00887 free(appInfo);
00888 return NULL;
00889 }
00890
00891 for(t = 0; t < l; t++)
00892 {
00893 appInfo->aflList[t] = (AFL*)malloc(sizeof(AFL));
00894 if(appInfo->aflList[t] == NULL)
00895 {
00896 FreeAPPINFO(appInfo);
00897 return NULL;
00898 }
00899 appInfo->aflList[t]->sfi = data[i++];
00900 appInfo->aflList[t]->recordStart = data[i++];
00901 appInfo->aflList[t]->recordEnd = data[i++];
00902 appInfo->aflList[t]->recordsOfflineAuth = data[i++];
00903 }
00904 }
00905 else i++;
00906 }
00907
00908 }
00909
00910 return appInfo;
00911 }
00912
00921 uint8_t GetSFIFromSELECT(const RAPDU *response)
00922 {
00923 uint8_t sfi = 0, i = 0;
00924
00925 if(response == NULL || response->repData == NULL)
00926 return 0;
00927
00928 while (i < response->lenData && response->repData[i] != 0x88) i++;
00929
00930 if (i < response->lenData - 2) sfi = response->repData[i + 2];
00931
00932 return sfi;
00933 }
00934
00943 TLV* GetPDOLFromFCI(const FCITemplate *fci)
00944 {
00945 uint8_t i;
00946 TLV *tmp;
00947
00948 if(fci == NULL || fci->fciData == NULL ||
00949 fci->fciData->count == 0 || fci->fciData->objects == NULL)
00950 return NULL;
00951
00952 for(i = 0; i < fci->fciData->count; i++)
00953 {
00954 tmp = fci->fciData->objects[i];
00955 if(tmp != NULL && tmp->tag1 == 0x9F && tmp->tag2 == 0x38)
00956 return tmp;
00957 }
00958
00959 return NULL;
00960 }
00961
00976 TLV* GetPDOL(const FCITemplate *fci)
00977 {
00978 TLV *pdol = NULL;
00979
00980 if(fci != NULL) pdol = GetPDOLFromFCI(fci);
00981 if(pdol == NULL)
00982 {
00983 pdol = (TLV*)malloc(sizeof(TLV));
00984 if(pdol == NULL) return NULL;
00985 pdol->value = NULL;
00986 pdol->len = 0;
00987 pdol->tag1 = 0x9F;
00988 pdol->tag2 = 0x38;
00989 }
00990
00991 return pdol;
00992 }
00993
01007 ByteArray* GetDataObject(uint8_t convention, uint8_t TC1,
01008 CARD_PDO pdo)
01009 {
01010 ByteArray* data = NULL;
01011 CAPDU* command;
01012 RAPDU* response;
01013 TLV* tlv;
01014
01015 command = MakeCommandC(CMD_GET_DATA, NULL, 0);
01016 if(command == NULL) return NULL;
01017 command->cmdHeader->p1 = 0x9F;
01018 command->cmdHeader->p2 = (uint8_t)pdo;
01019 response = TerminalSendT0Command(command, convention, TC1);
01020 FreeCAPDU(command);
01021 if(response == NULL) return NULL;
01022 if(response->repData == NULL)
01023 {
01024 FreeRAPDU(response);
01025 return NULL;
01026 }
01027
01028 tlv = ParseTLV(response->repData, response->lenData, 1);
01029 FreeRAPDU(response);
01030 if(tlv == NULL) return NULL;
01031 data = (ByteArray*)malloc(sizeof(ByteArray));
01032 data->len = tlv->len;
01033 data->bytes = NULL;
01034 if(tlv->len > 0 && tlv->value != NULL)
01035 {
01036 data->bytes = (uint8_t*)malloc(data->len * sizeof(uint8_t));
01037 if(data->bytes == NULL)
01038 {
01039 free(data);
01040 return NULL;
01041 }
01042 memcpy(data->bytes, tlv->value, data->len);
01043 }
01044
01045 return data;
01046 }
01047
01058 FCITemplate* ParseFCI(const uint8_t *data, uint8_t lenData)
01059 {
01060 FCITemplate *fci;
01061 uint8_t i, len;
01062
01063 if(data == NULL || lenData == 0)
01064 return NULL;
01065
01066 i = 0;
01067 if(lenData < 4 || data[i++] != 0x6F) return NULL;
01068 len = data[i++];
01069 if(len == EMV_EXTRA_LENGTH_BYTE) len = data[i++];
01070 if(len > lenData - 2) return NULL;
01071
01072
01073 if(data[i++] != 0x84) return NULL;
01074 len = data[i++];
01075 if(len == EMV_EXTRA_LENGTH_BYTE) len = data[i++];
01076 if(len > lenData - 4) return NULL;
01077
01078 fci = (FCITemplate*)malloc(sizeof(FCITemplate));
01079 if(fci == NULL) return NULL;
01080 fci->dfName = (uint8_t*)malloc(len * sizeof(uint8_t));
01081 if(fci->dfName == NULL)
01082 {
01083 free(fci);
01084 return NULL;
01085 }
01086 memcpy(fci->dfName, &data[i], len);
01087 fci->lenDFName = len;
01088 i += len;
01089
01090
01091 if(data[i++] != 0xA5)
01092 {
01093 FreeFCITemplate(fci);
01094 return NULL;
01095 }
01096 len = data[i++];
01097 if(len == EMV_EXTRA_LENGTH_BYTE) len = data[i++];
01098 if(len > (lenData - fci->lenDFName))
01099 {
01100 FreeFCITemplate(fci);
01101 return NULL;
01102 }
01103 fci->fciData = ParseManyTLV(&data[i], len);
01104 if(fci->fciData == NULL)
01105 {
01106 FreeFCITemplate(fci);
01107 return NULL;
01108 }
01109
01110 return fci;
01111 }
01112
01126 TLV* ParseTLV(const uint8_t *data, uint8_t lenData, uint8_t includeValue)
01127 {
01128 TLV* obj = NULL;
01129 uint8_t i = 0, j;
01130
01131 obj = (TLV*)malloc(sizeof(TLV));
01132 if(obj == NULL) return NULL;
01133 obj->value = NULL;
01134
01135 obj->tag1 = data[i++];
01136 if((obj->tag1 & 0x1F) == 0x1F)
01137 obj->tag2 = data[i++];
01138 else
01139 obj->tag2 = 0;
01140
01141 obj->len = data[i++];
01142 if(obj->len == EMV_EXTRA_LENGTH_BYTE) obj->len = data[i++];
01143
01144 if(includeValue != 0)
01145 {
01146 if(obj->len > lenData - 2)
01147 {
01148 free(obj);
01149 return NULL;
01150 }
01151
01152 obj->value = (uint8_t*)malloc(obj->len*sizeof(uint8_t));
01153 if(obj->value == NULL)
01154 {
01155 free(obj);
01156 return NULL;
01157 }
01158
01159 for(j = 0; j < obj->len; j++)
01160 obj->value[j] = data[i++];
01161 }
01162
01163 return obj;
01164 }
01165
01174 TLV* CopyTLV(const TLV *data)
01175 {
01176 TLV *clone;
01177
01178 if(data == NULL) return NULL;
01179
01180 clone = (TLV*)malloc(sizeof(TLV));
01181 if(clone == NULL) return NULL;
01182 clone->len = 0;
01183 clone->tag1 = data->tag1;
01184 clone->tag2 = data->tag2;
01185 clone->value = NULL;
01186
01187 if(data->value != NULL && (data->len > 0))
01188 {
01189 clone->value = (uint8_t*)malloc(data->len * sizeof(uint8_t));
01190 if(clone->value == NULL)
01191 {
01192 free(clone);
01193 return NULL;
01194 }
01195 memcpy(clone->value, data->value, data->len);
01196 clone->len = data->len;
01197 }
01198
01199 return clone;
01200 }
01201
01214 RECORD* ParseRECORD(const uint8_t *data, uint8_t lenData)
01215 {
01216 uint8_t i, len;
01217
01218 if(data == NULL || lenData == 0)
01219 return NULL;
01220
01221 i = 0;
01222 if(lenData < 4 || data[i++] != 0x70) return NULL;
01223 len = data[i++];
01224 if(len == EMV_EXTRA_LENGTH_BYTE) len = data[i++];
01225 if(len > lenData - 2) return NULL;
01226
01227 return ParseManyTLV(&data[i], len);
01228 }
01229
01244 uint8_t AddRECORD(RECORD *dest, const RECORD *src)
01245 {
01246 uint8_t i, k;
01247
01248 if(dest == NULL || src == NULL || src->objects == NULL) return RET_ERROR;
01249
01250 k = dest->count + src->count;
01251 dest->objects = (TLV**)realloc(dest->objects, k * sizeof(TLV*));
01252 if(dest->objects == NULL)
01253 return RET_ERROR;
01254
01255 for(i = 0; i < src->count; i++)
01256 {
01257 dest->objects[dest->count] = CopyTLV(src->objects[i]);
01258 if(dest->objects[dest->count] == NULL) return RET_ERROR;
01259 dest->count++;
01260 }
01261
01262 return 0;
01263 }
01264
01277 const TLV* GetTLVFromRECORD(RECORD *rec, uint8_t tag1, uint8_t tag2)
01278 {
01279 TLV *tlv;
01280 uint8_t i;
01281
01282 if(rec == NULL) return NULL;
01283 for(i = 0; i < rec->count; i++)
01284 {
01285 tlv = rec->objects[i];
01286 if(tlv != NULL && tlv->tag1 == tag1 && tlv->tag2 == tag2)
01287 return tlv;
01288 }
01289
01290 return NULL;
01291 }
01292
01304 RECORD* ParseManyTLV(const uint8_t *data, uint8_t lenData)
01305 {
01306 RECORD *rec;
01307 TLV *obj;
01308 uint8_t i;
01309
01310 if(data == NULL || lenData == 0)
01311 return NULL;
01312
01313 rec = (RECORD*)malloc(sizeof(RECORD));
01314 if(rec == NULL) return NULL;
01315 rec->count = 0;
01316 rec->objects = NULL;
01317 i = 0;
01318
01319 while(i < lenData)
01320 {
01321 obj = ParseTLV(&(data[i]), lenData - i, 1);
01322 if(obj == NULL)
01323 {
01324 FreeRECORD(rec);
01325 return NULL;
01326 }
01327 i += 2 + obj->len;
01328 if(obj->tag2 != 0) i++;
01329 if(obj->len > 127) i++;
01330
01331 rec->count++;
01332 rec->objects = (TLV**)realloc(rec->objects, rec->count * sizeof(TLV*));
01333 rec->objects[rec->count-1] = obj;
01334 }
01335
01336 return rec;
01337 }
01338
01339
01351 uint8_t AmountPositionInCDOLRecord(const RECORD *record)
01352 {
01353 uint8_t i;
01354 TLV *cdol1 = NULL, *obj;
01355
01356 if(record == NULL) return 0;
01357
01358 for(i = 0; i < record->count; i++)
01359 if(record->objects[i] != NULL && record->objects[i]->tag1 == 0x8C)
01360 {
01361 cdol1 = record->objects[i];
01362 break;
01363 }
01364
01365 if(cdol1 == NULL) return 0;
01366
01367 i = 0;
01368 while(i < cdol1->len)
01369 {
01370 obj = ParseTLV(&(cdol1->value[i]), cdol1->len - i, 0);
01371 if(obj == NULL) return 0;
01372
01373 if(obj->tag1 == 0x9F && obj->tag2 == 0x02)
01374 {
01375 free(obj);
01376 return i + 1;
01377 }
01378
01379 i += 2;
01380 if(obj->tag2 != 0) i++;
01381
01382 free(obj);
01383 }
01384
01385 return 0;
01386 }
01387
01397 ByteArray* SerializeTLV(const TLV* tlv)
01398 {
01399 ByteArray *stream;
01400 uint8_t *data;
01401 uint8_t len, i;
01402
01403 if(tlv == NULL) return NULL;
01404
01405 len = 1;
01406 if(tlv->tag2 != 0) len++;
01407 len++;
01408 if(tlv->len > 127) len++;
01409 if(tlv->value != NULL) len += tlv->len;
01410 data = (uint8_t*)malloc(len * sizeof(uint8_t));
01411 if(data == NULL) return NULL;
01412
01413 i = 0;
01414 data[i++] = tlv->tag1;
01415 if(tlv->tag2 != 0) data[i++] = tlv->tag2;
01416 if(tlv->len > 127) data[i++] = EMV_EXTRA_LENGTH_BYTE;
01417 data[i++] = tlv->len;
01418 if(tlv->value != NULL && tlv->len != 0)
01419 memcpy(&data[i], tlv->value, tlv->len);
01420
01421 stream = MakeByteArray(data, len);
01422 if(stream == NULL)
01423 {
01424 free(data);
01425 return NULL;
01426 }
01427
01428 return stream;
01429 }
01430
01436 void FreeTLV(TLV *data)
01437 {
01438 if(data == NULL) return;
01439
01440 if(data->value != NULL)
01441 {
01442 free(data->value);
01443 data->value = NULL;
01444 }
01445 free(data);
01446 }
01447
01453 void FreeRECORD(RECORD *data)
01454 {
01455 uint8_t i;
01456
01457 if(data == NULL) return;
01458
01459 if(data->objects != NULL)
01460 {
01461 for(i = 0; i < data->count; i++)
01462 if(data->objects[i] != NULL)
01463 {
01464 FreeTLV(data->objects[i]);
01465 data->objects[i] = NULL;
01466 }
01467 free(data->objects);
01468 data->objects = NULL;
01469 }
01470 free(data);
01471 }
01472
01478 void FreeRECORDList(RECORDList *data)
01479 {
01480 uint8_t i = 0;
01481
01482 if(data->objects != NULL)
01483 {
01484 for(i = 0; i < data->count; i++)
01485 if(data->objects[i] != NULL)
01486 {
01487 FreeRECORD(data->objects[i]);
01488 data->objects[i] = NULL;
01489 }
01490 free(data->objects);
01491 data->objects = NULL;
01492 }
01493 free(data);
01494 }
01495
01501 void FreeFCITemplate(FCITemplate *data)
01502 {
01503 if(data->fciData != NULL)
01504 {
01505 FreeRECORD(data->fciData);
01506 data->fciData = NULL;
01507 }
01508 if(data->dfName != NULL)
01509 {
01510 free(data->dfName);
01511 data->dfName = NULL;
01512 }
01513 free(data);
01514 }
01515
01521 void FreeFCIList(FCIList *data)
01522 {
01523 uint8_t i = 0;
01524
01525 if(data->objects != NULL)
01526 {
01527 for(i = 0; i < data->count; i++)
01528 if(data->objects[i] != NULL)
01529 {
01530 FreeFCITemplate(data->objects[i]);
01531 data->objects[i] = NULL;
01532 }
01533 free(data->objects);
01534 data->objects = NULL;
01535 }
01536 free(data);
01537 }
01538
01544 void FreeAPPINFO(APPINFO *data)
01545 {
01546 uint8_t i;
01547
01548 if(data == NULL) return;
01549
01550 if(data->aflList != NULL)
01551 {
01552 for(i = 0; i < data->count; i++)
01553 if(data->aflList[i] != NULL)
01554 {
01555 free(data->aflList[i]);
01556 data->aflList[i] = NULL;
01557 }
01558 free(data->aflList);
01559 data->aflList = NULL;
01560 }
01561 free(data);
01562 }
01563