The Smart Card Detective (SCD)
|
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