The Smart Card Detective (SCD)
serial.c
Go to the documentation of this file.
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 
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Defines