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