The Smart Card Detective (SCD)
|
00001 00037 #include <avr/sleep.h> 00038 #include <util/delay.h> 00039 #include <avr/wdt.h> 00040 #include <avr/eeprom.h> 00041 #include <string.h> 00042 #include <stdlib.h> 00043 00044 #include "apps.h" 00045 #include "emv.h" 00046 #include "terminal.h" 00047 #include "scd_hal.h" 00048 #include "serial.h" 00049 #include "scd_io.h" 00050 #include "scd_values.h" 00051 #include "VirtualSerial.h" 00052 00053 00055 #define EEPROM_SIZE 4096 00056 00058 static const char strAT_CRST[] = "AT+CRST"; 00059 static const char strAT_CTERM[] = "AT+CTERM"; 00060 static const char strAT_CLET[] = "AT+CLET"; 00061 static const char strAT_CGEE[] = "AT+CGEE"; 00062 static const char strAT_CEEE[] = "AT+CEEE"; 00063 static const char strAT_CGBM[] = "AT+CGBM"; 00064 static const char strAT_CCINIT[] = "AT+CCINIT"; 00065 static const char strAT_CCAPDU[] = "AT+CCAPDU"; 00066 static const char strAT_CCEND[] = "AT+CCEND"; 00067 static const char strAT_RBAD[] = "AT BAD\r\n"; 00068 static const char strAT_ROK[] = "AT OK\r\n"; 00069 00070 00087 char* ProcessSerialData(const char* data, log_struct_t *logger) 00088 { 00089 char *atparams = NULL; 00090 AT_CMD atcmd; 00091 uint8_t result = 0; 00092 char *str_ret = NULL; 00093 00094 result = ParseATCommand(data, &atcmd, &atparams); 00095 if(result != 0) 00096 return strdup(strAT_RBAD); 00097 00098 if(atcmd == AT_CRST) 00099 { 00100 // Reset the SCD within 1S so that host can reset connection 00101 StopVS(); 00102 wdt_enable(WDTO_1S); 00103 while(1); 00104 } 00105 else if(atcmd == AT_CTERM) 00106 { 00107 result = Terminal(logger); 00108 if (result == 0) 00109 str_ret = strdup(strAT_ROK); 00110 else 00111 str_ret = strdup(strAT_RBAD); 00112 } 00113 else if(atcmd == AT_CLET) 00114 { 00115 result = ForwardData(logger); 00116 if (result == 0) 00117 str_ret = strdup(strAT_ROK); 00118 else 00119 str_ret = strdup(strAT_RBAD); 00120 } 00121 else if(atcmd == AT_CGEE) 00122 { 00123 // Return EEPROM contents in Intel HEX format 00124 SendEEPROMHexVSerial(); 00125 str_ret = strdup(strAT_ROK); 00126 } 00127 else if(atcmd == AT_CEEE) 00128 { 00129 ResetEEPROM(); 00130 str_ret = strdup(strAT_ROK); 00131 } 00132 else if(atcmd == AT_CGBM) 00133 { 00134 RunBootloader(); 00135 str_ret = strdup(strAT_ROK); 00136 } 00137 else if(atcmd == AT_CCINIT) 00138 { 00139 result = TerminalVSerial(logger); 00140 if (result == 0) 00141 str_ret = NULL; 00142 else 00143 str_ret = strdup(strAT_RBAD); 00144 } 00145 else 00146 { 00147 str_ret = strdup(strAT_RBAD); 00148 } 00149 00150 return str_ret; 00151 } 00152 00165 uint8_t ParseATCommand(const char *data, AT_CMD *atcmd, char **atparams) 00166 { 00167 uint8_t len, pos; 00168 00169 *atparams = NULL; 00170 *atcmd = AT_NONE; 00171 00172 if(data == NULL || data[0] != 'A' || data[1] != 'T') 00173 return RET_ERR_PARAM; 00174 00175 len = strlen(data); 00176 if(len < 3) 00177 return RET_ERR_PARAM; 00178 00179 if(data[2] == '+') 00180 { 00181 if(strstr(data, strAT_CRST) == data) 00182 { 00183 *atcmd = AT_CRST; 00184 return 0; 00185 } 00186 else if(strstr(data, strAT_CTERM) == data) 00187 { 00188 *atcmd = AT_CTERM; 00189 return 0; 00190 } 00191 else if(strstr(data, strAT_CLET) == data) 00192 { 00193 *atcmd = AT_CLET; 00194 return 0; 00195 } 00196 else if(strstr(data, strAT_CGEE) == data) 00197 { 00198 *atcmd = AT_CGEE; 00199 return 0; 00200 } 00201 else if(strstr(data, strAT_CEEE) == data) 00202 { 00203 *atcmd = AT_CEEE; 00204 return 0; 00205 } 00206 else if(strstr(data, strAT_CGBM) == data) 00207 { 00208 *atcmd = AT_CGBM; 00209 return 0; 00210 } 00211 else if(strstr(data, strAT_CCINIT) == data) 00212 { 00213 *atcmd = AT_CCINIT; 00214 return 0; 00215 } 00216 else if(strstr(data, strAT_CCAPDU) == data) 00217 { 00218 *atcmd = AT_CCAPDU; 00219 pos = strlen(strAT_CCAPDU); 00220 if((strlen(data) > pos + 1) && data[pos] == '=') 00221 *atparams = &data[pos + 1]; 00222 return 0; 00223 } 00224 else if(strstr(data, strAT_CCEND) == data) 00225 { 00226 *atcmd = AT_CCEND; 00227 return 0; 00228 } 00229 } 00230 00231 return 0; 00232 } 00233 00234 00242 uint8_t SendEEPROMHexVSerial() 00243 { 00244 uint8_t eedata[32]; 00245 uint16_t eeaddr; 00246 char eestr[78]; 00247 uint8_t eesum; 00248 uint8_t i, k, t; 00249 00250 eeaddr = 0; 00251 memset(eestr, 0, 78); 00252 eestr[0] = ':'; 00253 eestr[1] = '2'; 00254 eestr[2] = '0'; 00255 eestr[7] = '0'; 00256 eestr[8] = '0'; 00257 eestr[75] = '\r'; 00258 eestr[76] = '\n'; 00259 00260 for(k = 0; k < EEPROM_SIZE / 32; k++) 00261 { 00262 eeprom_read_block(eedata, (void*)eeaddr, 32); 00263 eesum = 32 + ((eeaddr >> 8) & 0xFF) + (eeaddr & 0xFF); 00264 t = (eeaddr >> 12) & 0x0F; 00265 eestr[3] = (t < 0x0A) ? (t + '0') : (t + '7'); 00266 t = (eeaddr >> 8) & 0x0F; 00267 eestr[4] = (t < 0x0A) ? (t + '0') : (t + '7'); 00268 t = (eeaddr >> 4) & 0x0F; 00269 eestr[5] = (t < 0x0A) ? (t + '0') : (t + '7'); 00270 t = eeaddr & 0x0F; 00271 eestr[6] = (t < 0x0A) ? (t + '0') : (t + '7'); 00272 00273 for(i = 0; i < 32; i++) 00274 { 00275 eesum = eesum + eedata[i]; 00276 t = (eedata[i] >> 4) & 0x0F; 00277 eestr[9 + i * 2] = (t < 0x0A) ? (t + '0') : (t + '7'); 00278 t = eedata[i] & 0x0F; 00279 eestr[10 + i * 2] = (t < 0x0A) ? (t + '0') : (t + '7'); 00280 } 00281 00282 eesum = (uint8_t)((eesum ^ 0xFF) + 1); 00283 t = (eesum >> 4) & 0x0F; 00284 eestr[73] = (t < 0x0A) ? (t + '0') : (t + '7'); 00285 t = eesum & 0x0F; 00286 eestr[74] = (t < 0x0A) ? (t + '0') : (t + '7'); 00287 00288 if(SendHostData(eestr)) 00289 return RET_ERROR; 00290 00291 eeaddr = eeaddr + 32; 00292 } 00293 00294 memset(eestr, 0, 78); 00295 eestr[0] = ':'; 00296 eestr[1] = '0'; 00297 eestr[2] = '0'; 00298 eestr[3] = '0'; 00299 eestr[4] = '0'; 00300 eestr[5] = '0'; 00301 eestr[6] = '0'; 00302 eestr[7] = '0'; 00303 eestr[8] = '1'; 00304 eestr[9] = 'F'; 00305 eestr[10] = 'F'; 00306 eestr[11] = '\r'; 00307 eestr[12] = '\n'; 00308 if(SendHostData(eestr)) 00309 return RET_ERROR; 00310 00311 return 0; 00312 } 00313 00314 00327 uint8_t TerminalVSerial(log_struct_t *logger) 00328 { 00329 uint8_t convention, proto, TC1, TA3, TB3; 00330 uint8_t tmp, i, lparams, ldata, result; 00331 char *buf, *atparams = NULL; 00332 char reply[512]; 00333 uint8_t data[256]; 00334 AT_CMD atcmd; 00335 RAPDU *response = NULL; 00336 CAPDU *command = NULL; 00337 00338 // First thing is to respond to the VS host since this method 00339 // was presumably called based on an AT+CINIT command 00340 if(!IsICCInserted()) 00341 { 00342 fprintf(stderr, "ICC not inserted\n"); 00343 _delay_ms(500); 00344 return RET_ERROR; 00345 } 00346 00347 result = ResetICC(0, &convention, &proto, &TC1, &TA3, &TB3, logger); 00348 if(result) 00349 { 00350 fprintf(stderr, "ICC reset failed\n"); 00351 _delay_ms(500); 00352 fprintf(stderr, "result: %2X\n", result); 00353 _delay_ms(500); 00354 goto enderror; 00355 } 00356 00357 if(proto != 0) // Not implemented yet ... 00358 { 00359 fprintf(stderr, "bad ICC proto\n"); 00360 _delay_ms(500); 00361 goto enderror; 00362 } 00363 00364 // If all is well so far announce the host so we get more data 00365 SendHostData(strAT_ROK); 00366 00367 // Loop continuously until the host ends the transaction or 00368 // we get an error 00369 while(1) 00370 { 00371 buf = GetHostData(255); 00372 if(buf == NULL) 00373 { 00374 _delay_ms(100); 00375 continue; 00376 } 00377 00378 tmp = ParseATCommand(buf, &atcmd, &atparams); 00379 lparams = strlen(atparams); 00380 00381 if(atcmd == AT_CCEND) 00382 { 00383 result = 0; 00384 break; 00385 } 00386 else if(atcmd != AT_CCAPDU || atparams == NULL || lparams < 10 || (lparams % 2) != 0) 00387 { 00388 SendHostData(strAT_RBAD); 00389 free(buf); 00390 continue; 00391 } 00392 00393 memset(data, 0, 256); 00394 for(i = 0; i < lparams/2; i++) 00395 { 00396 data[i] = hexCharsToByte(atparams[2*i], atparams[2*i + 1]); 00397 } 00398 free(buf); 00399 00400 ldata = (lparams - 10) / 2; 00401 command = MakeCommand( 00402 data[0], data[1], data[2], data[3], data[4], 00403 &data[5], ldata); 00404 if(command == NULL) 00405 { 00406 SendHostData(strAT_RBAD); 00407 continue; 00408 } 00409 00410 // Send the command 00411 response = TerminalSendT0Command(command, convention, TC1, logger); 00412 FreeCAPDU(command); 00413 if(response == NULL) 00414 { 00415 FreeCAPDU(command); 00416 SendHostData(strAT_RBAD); 00417 continue; 00418 } 00419 00420 memset(reply, 0, 512); 00421 reply[0] = nibbleToHexChar(response->repStatus->sw1, 1); 00422 reply[1] = nibbleToHexChar(response->repStatus->sw1, 0); 00423 reply[2] = nibbleToHexChar(response->repStatus->sw2, 1); 00424 reply[3] = nibbleToHexChar(response->repStatus->sw2, 0); 00425 for(i = 0; i < response->lenData; i++) 00426 { 00427 reply[4 + i*2] = nibbleToHexChar(response->repData[i], 1); 00428 reply[5 + i*2] = nibbleToHexChar(response->repData[i], 0); 00429 } 00430 reply[4 + i] = '\r'; 00431 reply[5 + i] = '\n'; 00432 FreeRAPDU(response); 00433 SendHostData(reply); 00434 } // end while(1) 00435 00436 enderror: 00437 DeactivateICC(); 00438 if(logger) 00439 { 00440 LogByte1(logger, LOG_ICC_DEACTIVATED, 0); 00441 if(lcdAvailable) 00442 fprintf(stderr, "Writing Log\n"); 00443 WriteLogEEPROM(logger); 00444 ResetLogger(logger); 00445 } 00446 00447 return result; 00448 } 00449 00450 00459 uint8_t hexCharsToByte(char c1, char c2) 00460 { 00461 uint8_t result = 0; 00462 00463 if(c1 >= '0' && c1 <= '9') 00464 result = c1 - '0'; 00465 else if(c1 >= 'A' && c1 <= 'F') 00466 result = c1 - '7'; 00467 else if(c1 >= 'a' && c1 <= 'f') 00468 result = c1 - 'W'; 00469 else 00470 return 0; 00471 00472 result = result << 4; 00473 00474 if(c2 >= '0' && c2 <= '9') 00475 result |= c2 - '0'; 00476 else if(c2 >= 'A' && c2 <= 'F') 00477 result |= c2 - '7'; 00478 else if(c2 >= 'a' && c2 <= 'f') 00479 result |= c2 - 'W'; 00480 else 00481 return 0; 00482 00483 return result; 00484 } 00485 00494 char nibbleToHexChar(uint8_t b, uint8_t high) 00495 { 00496 char result = '0'; 00497 00498 if(high) 00499 b = (b & 0xF0) >> 4; 00500 else 00501 b = b & 0x0F; 00502 00503 if(b < 10) 00504 result = b + '0'; 00505 else if(b < 16) 00506 result = b + '7'; 00507 00508 return result; 00509 } 00510