The Smart Card Detective (SCD)
|
00001 00036 // #define F_CPU 16000000UL // Not needed if defined in Makefile 00037 00038 // this is needed for the delay on the new avr-libc-1.7.0 00039 #ifndef __DELAY_BACKWARD_COMPATIBLE__ 00040 #define __DELAY_BACKWARD_COMPATIBLE__ 00041 #endif 00042 00043 #include <avr/io.h> 00044 #include <avr/interrupt.h> 00045 #include <avr/sleep.h> 00046 #include <avr/power.h> 00047 #include <avr/eeprom.h> 00048 #include <string.h> 00049 #include <util/delay.h> 00050 #include <util/delay_basic.h> 00051 #include <stdlib.h> 00052 #include <avr/wdt.h> 00053 00054 #include "apps.h" 00055 #include "emv.h" 00056 #include "scd_hal.h" 00057 #include "scd_io.h" 00058 #include "scd.h" 00059 #include "scd_logger.h" 00060 #include "utils.h" 00061 #include "emv_values.h" 00062 #include "scd_values.h" 00063 #include "VirtualSerial.h" 00064 #include "serial.h" 00065 00067 #define LCD_ENABLED 1 00068 00070 #define DEBUG 0 00071 00073 #define ICC_PRES_INT_ENABLE 1 00074 00075 // If there are any assembler routines, they can be used 00076 // by declaring them as below 00077 // extern void StartClkICC(void); 00078 00079 /* Functions used in the main program */ 00080 //static inline void StopTerminal(const char *string); 00081 00082 00083 /* Static variables */ 00084 #if LCD_ENABLED 00085 static char* strATRSent = "ATR Sent"; 00086 static char* strError = "Error Ocurred"; 00087 static char* strDataSent = "Data Sent"; 00088 static char* strScroll = "BC to scroll"; 00089 static char* strSelect = "BD to select"; 00090 static char* strAvailable = "Avail. apps:"; 00091 #endif 00092 log_struct_t scd_logger; // logger structure 00093 00094 /* Global variables */ 00095 uint8_t warmResetByte; 00096 uint8_t lcdAvailable; // non-zero if LCD is working 00097 uint8_t nCounter; // number of transactions 00098 uint8_t selected; // ID of application selected 00099 uint8_t bootkey; // used for bootloader jump 00100 uint16_t revision = 0x24; // current revision number, saved as BCD 00101 00102 // Use the LCD as stderr (see main) 00103 FILE lcd_str = FDEV_SETUP_STREAM(LcdPutchar, NULL, _FDEV_SETUP_WRITE); 00104 00105 00109 int main(void) 00110 { 00111 uint8_t sreg; 00112 00113 // Init SCD 00114 InitSCD(); 00115 00116 // Check the hardware 00117 //TestHardware(); 00118 00119 // Select application if BB is pressed while restarting 00120 if(GetButtonB() == 0) 00121 { 00122 selected = SelectApplication(); 00123 00124 if(selected == APP_ERASE_EEPROM) 00125 { 00126 Led2On(); 00127 ResetEEPROM(); 00128 Led2Off(); 00129 wdt_enable(WDTO_15MS); 00130 } 00131 else 00132 { 00133 sreg = SREG; 00134 cli(); 00135 eeprom_write_byte((uint8_t*)EEPROM_APPLICATION, selected); 00136 SREG = sreg; 00137 } 00138 00139 // restart micro-second counter every time we select an application 00140 ResetCounter(); 00141 00142 // restart SCD so that LCD power is reduced (small trick) 00143 wdt_enable(WDTO_15MS); 00144 } 00145 else 00146 { 00147 sreg = SREG; 00148 cli(); 00149 selected = eeprom_read_byte((uint8_t*)EEPROM_APPLICATION); 00150 SREG = sreg; 00151 } 00152 00153 // continuously run the selected application 00154 // add here any applications that can be selected from the user menu 00155 while(1) 00156 { 00157 switch(selected) 00158 { 00159 case APP_VIRTUAL_SERIAL_PORT: 00160 VirtualSerial(&scd_logger); 00161 break; 00162 00163 case APP_FORWARD: 00164 ForwardData(&scd_logger); 00165 break; 00166 00167 case APP_FILTER_GENERATEAC: 00168 FilterGenerateAC(&scd_logger); 00169 break; 00170 00171 case APP_TERMINAL: 00172 Terminal(&scd_logger); 00173 break; 00174 00175 default: 00176 selected = APP_VIRTUAL_SERIAL_PORT; 00177 eeprom_write_byte((uint8_t*)EEPROM_APPLICATION, selected); 00178 VirtualSerial(&scd_logger); 00179 } 00180 } 00181 00182 // if needed disable wdt to avoid restart 00183 // wdt_disable(); 00184 00185 SwitchLeds(); 00186 } 00187 00201 uint8_t SelectApplication() 00202 { 00203 volatile uint8_t tmp; 00204 uint8_t i; 00205 00206 if(!lcdAvailable) return 0; 00207 00208 InitLCD(); 00209 fprintf(stderr, "\n"); 00210 00211 while(1){ 00212 fprintf(stderr, "%s\n", strScroll); 00213 do{ 00214 tmp = GetButton(); 00215 }while((tmp & BUTTON_C) == 0); 00216 _delay_ms(500); 00217 00218 fprintf(stderr, "%s\n", strSelect); 00219 do{ 00220 tmp = GetButton(); 00221 }while((tmp & BUTTON_C) == 0); 00222 _delay_ms(500); 00223 00224 fprintf(stderr, "%s\n", strAvailable); 00225 do{ 00226 tmp = GetButton(); 00227 }while((tmp & BUTTON_C) == 0); 00228 _delay_ms(500); 00229 00230 for(i = 0; i < APPLICATION_COUNT; i++) 00231 { 00232 fprintf(stderr, "%s\n", appStrings[i]); 00233 while(1) 00234 { 00235 tmp = GetButton(); 00236 if((tmp & BUTTON_D) != 0) return (i + 1); 00237 if((tmp & BUTTON_C) != 0) break; 00238 } 00239 _delay_ms(500); 00240 } 00241 } 00242 00243 return 0; 00244 } 00245 00246 00252 void InitSCD() 00253 { 00254 // disable any interrupts 00255 cli(); 00256 EICRA = 0; 00257 EICRB = 0; 00258 EIFR = 0xFF; 00259 EIMSK = 0; 00260 00261 // Disable WDT to keep safe operation 00262 DisableWDT(); 00263 00264 // Reset log structure (the one in SRAM) 00265 ResetLogger(&scd_logger); 00266 00267 // Read ms counter in order to continue from last value 00268 // We add the estimated startup time of 4 ms 00269 SetCounter(eeprom_read_dword((uint32_t*)EEPROM_TIMER_T2) + 4); 00270 00271 // Ports setup 00272 DDRB = 0x00; 00273 00274 DDRC = 0x00; 00275 PORTC = 0x18; // PC4 with internal pull-up (Terminal I/O) 00276 // PC3 with internal pull-up (terminal clock) 00277 00278 DDRD = 0x80; 00279 PORTD = 0x83; // PD7 high (ICC VCC) , PD1 pull-up 00280 // (ICC switch), PD0 pull-up (terminal reset) 00281 00282 DDRF &= 0xF0; 00283 PORTF |= 0x0F; // enable pull-up for buttons 00284 00285 // change CLK Prescaler value 00286 clock_prescale_set(clock_div_1); 00287 00288 // enable counter T2 00289 StartTimerT2(); 00290 00291 // light power led 00292 Led4On(); 00293 00294 //#if ICC_PRES_INT_ENABLE 00295 // EnableICCInsertInterrupt(); 00296 //#endif 00297 00298 // Read Warm byte info from EEPROM 00299 warmResetByte = eeprom_read_byte((uint8_t*)EEPROM_WARM_RESET); 00300 00301 // Read number of transactions in EEPROM 00302 nCounter = eeprom_read_byte((uint8_t*)EEPROM_COUNTER); 00303 00304 // Check LCD status and use as stderr if status OK 00305 if(CheckLCD()) 00306 { 00307 stderr = NULL; 00308 lcdAvailable = 0; 00309 } 00310 else 00311 { 00312 stderr = &lcd_str; 00313 lcdAvailable = 1; 00314 // disable LCD power 00315 LCDOff(); 00316 } 00317 00318 // Disable most modules; they should be re-enabled when needed 00319 power_adc_disable(); 00320 power_spi_disable(); 00321 power_twi_disable(); 00322 power_usart1_disable(); 00323 power_usb_disable(); 00324 00325 // Enable interrupts 00326 sei(); 00327 00328 // Disable INT0 and INT1 00329 EIMSK &= ~(_BV(INT0)); 00330 EIMSK &= ~(_BV(INT1)); 00331 } 00332 00333 00334 /* Intrerupts */ 00335 00341 ISR(INT0_vect) 00342 { 00343 // disable wdt 00344 DisableWDT(); 00345 00346 // disable INT0 00347 DisableTerminalResetInterrupt(); 00348 00349 // Log the event 00350 LogByte1(&scd_logger, LOG_TERMINAL_RST_LOW, 0); 00351 00352 // Write the log to EEPROM and clear its contents 00353 WriteLogEEPROM(&scd_logger); 00354 ResetLogger(&scd_logger); 00355 00356 // check for warm vs cold reset 00357 if(GetTerminalFreq()) 00358 { 00359 // warm reset 00360 warmResetByte = eeprom_read_byte((uint8_t*)EEPROM_WARM_RESET); 00361 00362 if(warmResetByte == WARM_RESET_VALUE) 00363 { 00364 // we already had a warm reset so go to initial state 00365 eeprom_write_byte((uint8_t*)EEPROM_WARM_RESET, 0); 00366 while(EECR & _BV(EEPE)); 00367 } 00368 else 00369 { 00370 // set 0xAA in EEPROM meaning we have a warm reset 00371 eeprom_write_byte((uint8_t*)EEPROM_WARM_RESET, WARM_RESET_VALUE); 00372 while(EECR & _BV(EEPE)); 00373 } 00374 } 00375 else 00376 { 00377 eeprom_write_byte((uint8_t*)EEPROM_WARM_RESET, 0); 00378 while(EECR & _BV(EEPE)); 00379 } 00380 00381 // re-enable wdt to restart device 00382 wdt_enable(WDTO_15MS); 00383 00384 // Update timer value in EEPROM while we wait for restart 00385 eeprom_update_dword((uint32_t*)EEPROM_TIMER_T2, GetCounter()); 00386 } 00387 00392 ISR(INT1_vect) 00393 { 00394 if(bit_is_set(PIND, PD1)) 00395 { 00396 Led3On(); 00397 } 00398 else 00399 { 00400 Led3Off(); 00401 DeactivateICC(); 00402 } 00403 00404 } 00405 00409 ISR(WDT_vect) 00410 { 00411 // Log the event 00412 LogByte1(&scd_logger, LOG_WDT_RESET, 0); 00413 00414 // Write the log to EEPROM and clear its contents 00415 WriteLogEEPROM(&scd_logger); 00416 ResetLogger(&scd_logger); 00417 } 00418 00419 00425 ISR(TIMER3_COMPA_vect, ISR_NAKED) 00426 { 00427 reti(); // Do nothing, used just to wake up the CPU 00428 } 00429 00444 //ISR(TIMER2_COMPA_vect) 00445 //{ 00446 // IncrementCounter(); 00447 //} 00448 00456 void BootloaderJumpCheck() 00457 { 00458 uint16_t bootloader_addr; 00459 uint8_t fuse_high; 00460 00461 // Disable wdt in case it was enabled 00462 wdt_disable(); 00463 00464 // If the reset source was the bootloader and the key is correct, clear it and jump to the bootloader 00465 if ((MCUSR & (1<<WDRF)) && (bootkey == MAGIC_BOOT_KEY)) 00466 { 00467 bootkey = 0; 00468 00469 fuse_high = boot_lock_fuse_bits_get(GET_HIGH_FUSE_BITS); 00470 fuse_high = (fuse_high & 0x07) >> 1; 00471 if(fuse_high == 0) 00472 bootloader_addr = 0xF000; 00473 else if(fuse_high == 1) 00474 bootloader_addr = 0xF800; 00475 else if(fuse_high == 2) 00476 bootloader_addr = 0xFC00; 00477 else if(fuse_high == 3) 00478 bootloader_addr = 0xFE00; 00479 00480 ((void (*)(void))bootloader_addr)(); 00481 } 00482 } 00483 00487 void TestHardware() 00488 { 00489 #if LCD_ENABLED 00490 char* strBA = "Press BA"; 00491 char* strBB = "Press BB"; 00492 char* strBC = "Press BC"; 00493 char* strBD = "Press BD"; 00494 char* strAOK = "All fine!"; 00495 #endif 00496 00497 00498 Led1On(); 00499 _delay_ms(50); 00500 Led1Off(); 00501 Led2On(); 00502 _delay_ms(50); 00503 Led2Off(); 00504 Led3On(); 00505 _delay_ms(50); 00506 Led3Off(); 00507 Led4On(); 00508 _delay_ms(50); 00509 Led4Off(); 00510 00511 #if LCD_ENABLED 00512 if(lcdAvailable) 00513 { 00514 InitLCD(); 00515 fprintf(stderr, "\n"); 00516 00517 WriteStringLCD(strBA, strlen(strBA)); 00518 while(bit_is_set(PINF, PF3)); 00519 00520 WriteStringLCD(strBB, strlen(strBB)); 00521 while(bit_is_set(PINF, PF2)); 00522 00523 WriteStringLCD(strBC, strlen(strBC)); 00524 while(bit_is_set(PINF, PF1)); 00525 00526 WriteStringLCD(strBD, strlen(strBD)); 00527 while(bit_is_set(PINF, PF0)); 00528 00529 WriteStringLCD(strAOK, strlen(strAOK)); 00530 } 00531 #endif 00532 } 00533 00542 void TestSCDTerminal() 00543 { 00544 char strLCD[16]; 00545 uint8_t tmpa; 00546 00547 //start Timer for Terminal 00548 StartCounterTerminal(); 00549 00550 // wait for Terminal CLK and send ATR 00551 while(ReadCounterTerminal() < 100); 00552 Led1On(); 00553 while(GetTerminalResetLine() == 0); 00554 Led2On(); 00555 LoopTerminalETU(10); 00556 SendT0ATRTerminal(0, 0x0F, NULL); 00557 Led1Off(); 00558 00559 00560 #if LCD_ENABLED 00561 if(lcdAvailable) 00562 { 00563 InitLCD(); 00564 fprintf(stderr, "\n"); 00565 WriteStringLCD(strATRSent, strlen(strATRSent)); 00566 } 00567 #endif 00568 00569 while(1) 00570 { 00571 // Get SELECT command for "1PAY.SYS.DDF01" 00572 tmpa = GetByteTerminalParity(0, (uint8_t*)&strLCD[0], MAX_WAIT_TERMINAL); // CLA = 0x00 00573 tmpa = GetByteTerminalParity(0, (uint8_t*)&strLCD[1], MAX_WAIT_TERMINAL); // INS = 0xA4 00574 tmpa = GetByteTerminalParity(0, (uint8_t*)&strLCD[2], MAX_WAIT_TERMINAL); // P1 = 0x04 00575 tmpa = GetByteTerminalParity(0, (uint8_t*)&strLCD[3], MAX_WAIT_TERMINAL); // P2 = 0x00 00576 tmpa = GetByteTerminalParity(0, (uint8_t*)&strLCD[4], MAX_WAIT_TERMINAL); // P3 = 0x0E 00577 00578 strLCD[5] = 0; 00579 00580 Led1On(); 00581 Led2Off(); 00582 00583 // Send INS (procedure byte) back 00584 LoopTerminalETU(20); 00585 //SendByteTerminalNoParity(0xA4, 0); 00586 SendByteTerminalParity(0xA4, 0); 00587 00588 Led1Off(); 00589 Led2On(); 00590 00591 // Get Select command data => "1PAY.SYS.DDF01" 00592 tmpa = GetByteTerminalParity(0, (uint8_t*)&strLCD[0], MAX_WAIT_TERMINAL); 00593 tmpa = GetByteTerminalParity(0, (uint8_t*)&strLCD[1], MAX_WAIT_TERMINAL); 00594 tmpa = GetByteTerminalParity(0, (uint8_t*)&strLCD[2], MAX_WAIT_TERMINAL); 00595 tmpa = GetByteTerminalParity(0, (uint8_t*)&strLCD[3], MAX_WAIT_TERMINAL); 00596 tmpa = GetByteTerminalParity(0, (uint8_t*)&strLCD[4], MAX_WAIT_TERMINAL); 00597 tmpa = GetByteTerminalParity(0, (uint8_t*)&strLCD[5], MAX_WAIT_TERMINAL); 00598 tmpa = GetByteTerminalParity(0, (uint8_t*)&strLCD[6], MAX_WAIT_TERMINAL); 00599 tmpa = GetByteTerminalParity(0, (uint8_t*)&strLCD[7], MAX_WAIT_TERMINAL); 00600 tmpa = GetByteTerminalParity(0, (uint8_t*)&strLCD[8], MAX_WAIT_TERMINAL); 00601 tmpa = GetByteTerminalParity(0, (uint8_t*)&strLCD[9], MAX_WAIT_TERMINAL); 00602 tmpa = GetByteTerminalParity(0, (uint8_t*)&strLCD[10], MAX_WAIT_TERMINAL); 00603 tmpa = GetByteTerminalParity(0, (uint8_t*)&strLCD[11], MAX_WAIT_TERMINAL); 00604 tmpa = GetByteTerminalParity(0, (uint8_t*)&strLCD[12], MAX_WAIT_TERMINAL); 00605 tmpa = GetByteTerminalParity(0, (uint8_t*)&strLCD[13], MAX_WAIT_TERMINAL); 00606 strLCD[14] = 0; 00607 00608 Led1On(); 00609 Led2Off(); 00610 00611 #if LCD_ENABLED 00612 if(lcdAvailable) 00613 { 00614 if(tmpa != 0) 00615 WriteStringLCD(strError, strlen(strError)); 00616 else 00617 WriteStringLCD(strLCD, 14); 00618 } 00619 #endif 00620 00621 // Send "6104" (procedure bytes) back 00622 SendByteTerminalParity(0x61, 0); 00623 LoopTerminalETU(2); 00624 SendByteTerminalParity(0x04, 0); 00625 00626 Led1Off(); 00627 Led2On(); 00628 00629 // Get GetResponse from Reader 00630 tmpa = GetByteTerminalParity(0, (uint8_t*)&strLCD[0], MAX_WAIT_TERMINAL); 00631 tmpa = GetByteTerminalParity(0, (uint8_t*)&strLCD[1], MAX_WAIT_TERMINAL); 00632 tmpa = GetByteTerminalParity(0, (uint8_t*)&strLCD[2], MAX_WAIT_TERMINAL); 00633 tmpa = GetByteTerminalParity(0, (uint8_t*)&strLCD[3], MAX_WAIT_TERMINAL); 00634 tmpa = GetByteTerminalParity(0, (uint8_t*)&strLCD[4], MAX_WAIT_TERMINAL); 00635 strLCD[5] = 0; 00636 00637 Led1On(); 00638 Led2Off(); 00639 00640 // Send some data back as response to select command 00641 LoopTerminalETU(20); 00642 SendByteTerminalParity(0xC0, 0); 00643 LoopTerminalETU(2); 00644 00645 SendByteTerminalParity(0xDE, 0); 00646 LoopTerminalETU(2); 00647 00648 SendByteTerminalParity(0xAD, 0); 00649 LoopTerminalETU(2); 00650 00651 SendByteTerminalParity(0xBE, 0); 00652 LoopTerminalETU(2); 00653 00654 SendByteTerminalParity(0xEF, 0); 00655 LoopTerminalETU(2); 00656 00657 SendByteTerminalParity(0x90, 0); 00658 LoopTerminalETU(2); 00659 00660 SendByteTerminalParity(0x00, 0); 00661 00662 Led1Off(); 00663 Led2On(); 00664 00665 #if LCD_ENABLED 00666 if(lcdAvailable) 00667 WriteStringLCD(strDataSent, strlen(strDataSent)); 00668 #endif 00669 } 00670 } 00671 00680 void TestSCDICC(log_struct_t *logger) 00681 { 00682 uint8_t inverse, proto, TC1, TA3, TB3; 00683 uint8_t byte; 00684 00685 // Power ICC and get ATR 00686 if(ResetICC(0, &inverse, &proto, &TC1, &TA3, &TB3, logger)) return; 00687 00688 // Send SELECT command (no data yet) 00689 LoopICCETU(5); 00690 SendByteICCParity(0x00, inverse); 00691 LoopICCETU(2); 00692 SendByteICCParity(0xA4, inverse); 00693 LoopICCETU(2); 00694 SendByteICCParity(0x04, inverse); 00695 LoopICCETU(2); 00696 SendByteICCParity(0x00, inverse); 00697 LoopICCETU(2); 00698 SendByteICCParity(0x0E, inverse); 00699 00700 // Get INS back 00701 LoopICCETU(1); 00702 GetByteICCParity(inverse, &byte); 00703 if(byte != 0xA4) return; 00704 00705 // Send "1PAY.SYS.DDF01" 00706 LoopICCETU(5); 00707 SendByteICCParity(0x31, inverse); 00708 LoopICCETU(2); 00709 SendByteICCParity(0x50, inverse); 00710 LoopICCETU(2); 00711 SendByteICCParity(0x41, inverse); 00712 LoopICCETU(2); 00713 SendByteICCParity(0x59, inverse); 00714 LoopICCETU(2); 00715 SendByteICCParity(0x2E, inverse); 00716 LoopICCETU(2); 00717 SendByteICCParity(0x53, inverse); 00718 LoopICCETU(2); 00719 SendByteICCParity(0x59, inverse); 00720 LoopICCETU(2); 00721 SendByteICCParity(0x53, inverse); 00722 LoopICCETU(2); 00723 SendByteICCParity(0x2E, inverse); 00724 LoopICCETU(2); 00725 SendByteICCParity(0x44, inverse); 00726 LoopICCETU(2); 00727 SendByteICCParity(0x44, inverse); 00728 LoopICCETU(2); 00729 SendByteICCParity(0x46, inverse); 00730 LoopICCETU(2); 00731 SendByteICCParity(0x30, inverse); 00732 LoopICCETU(2); 00733 SendByteICCParity(0x31, inverse); 00734 00735 // Expect 0x61, 0xXX 00736 LoopICCETU(1); 00737 GetByteICCParity(inverse, &byte); 00738 if(byte != 0x61) return; 00739 LoopICCETU(1); 00740 GetByteICCParity(inverse, &byte); 00741 00742 // Send GET Response 00743 LoopICCETU(5); 00744 SendByteICCParity(0x00, inverse); 00745 LoopICCETU(2); 00746 SendByteICCParity(0xC0, inverse); 00747 LoopICCETU(2); 00748 SendByteICCParity(0x00, inverse); 00749 LoopICCETU(2); 00750 SendByteICCParity(0x00, inverse); 00751 LoopICCETU(2); 00752 SendByteICCParity(byte, inverse); 00753 00754 // Data should follow from the ICC... 00755 Led1On(); 00756 #if LCD_ENABLED 00757 if(lcdAvailable) 00758 { 00759 InitLCD(); 00760 fprintf(stderr, "\n"); 00761 WriteStringLCD(strDataSent, strlen(strDataSent)); 00762 } 00763 #endif 00764 } 00765 00769 void SwitchLeds() 00770 { 00771 while(1) 00772 { 00773 _delay_ms(500); 00774 Led1On(); 00775 Led2Off(); 00776 _delay_ms(500); 00777 Led1Off(); 00778 Led2On(); 00779 } 00780 } 00781