1 //----------------------------------------------------------------------------- 
   2 // Copyright (C) 2018 iceman 
   4 // This code is licensed to you under the terms of the GNU GPL, version 2 or, 
   5 // at your option, any later version. See the LICENSE.txt file for the text of 
   7 //----------------------------------------------------------------------------- 
   8 // Proxmark3 RDV40 Smartcard module commands 
   9 //----------------------------------------------------------------------------- 
  10 #include "cmdsmartcard.h" 
  11 #include "smartcard.h" 
  13 #include "protocols.h" 
  16 static int CmdHelp(const char *Cmd
); 
  18 int usage_sm_raw(void) { 
  19         PrintAndLog("Usage: sc raw [h|r|c] d <0A 0B 0C ... hex>"); 
  20         PrintAndLog("       h          :  this help"); 
  21         PrintAndLog("       r          :  do not read response"); 
  22         PrintAndLog("       a          :  active signal field ON without select"); 
  23         PrintAndLog("       s          :  active signal field ON with select"); 
  24         PrintAndLog("       t          :  executes TLV decoder if it is possible"); 
  25         PrintAndLog("       d <bytes>  :  bytes to send"); 
  27         PrintAndLog("Examples:"); 
  28         PrintAndLog("        sc raw d 11223344");        
  31 int usage_sm_reader(void) { 
  32         PrintAndLog("Usage: sc reader [h|s]"); 
  33         PrintAndLog("       h          :  this help"); 
  34         PrintAndLog("       s          :  silent (no messages)"); 
  36         PrintAndLog("Examples:"); 
  37         PrintAndLog("        sc reader");        
  40 int usage_sm_info(void) { 
  41         PrintAndLog("Usage: sc info [h|s]"); 
  42         PrintAndLog("       h          :  this help"); 
  43         PrintAndLog("       s          :  silent (no messages)"); 
  45         PrintAndLog("Examples:"); 
  46         PrintAndLog("        sc info"); 
  49 int usage_sm_upgrade(void) { 
  50         PrintAndLog("Upgrade firmware"); 
  51         PrintAndLog("Usage: sc upgrade f <file name>"); 
  52         PrintAndLog("       h               :  this help"); 
  53         PrintAndLog("       f <filename>    :  firmware file name"); 
  55         PrintAndLog("Examples:"); 
  56         PrintAndLog("        sc upgrade f myfile"); 
  58         PrintAndLog("WARNING - Dangerous command, do wrong and you will brick the smart card socket"); 
  61 int usage_sm_setclock(void) { 
  62         PrintAndLog("Usage: sc setclock [h] c <clockspeed>"); 
  63         PrintAndLog("       h          :  this help"); 
  64         PrintAndLog("       c <>       :  clockspeed (0 = 16mhz, 1=8mhz, 2=4mhz) "); 
  66         PrintAndLog("Examples:"); 
  67         PrintAndLog("        sc setclock c 2"); 
  71 int CmdSmartRaw(const char *Cmd
) { 
  75         bool active_select 
= false; 
  77         bool errors 
= false, reply 
= true, decodeTLV 
= false, breakloop 
= false; 
  78         uint8_t data
[USB_CMD_DATA_SIZE
] = {0x00}; 
  80         while (param_getchar(Cmd
, cmdp
) != 0x00 && !errors
) { 
  81                 switch (tolower(param_getchar(Cmd
, cmdp
))) { 
  82                 case 'h': return usage_sm_raw(); 
 100                         switch (param_gethex_to_eol(Cmd
, cmdp
+1, data
, sizeof(data
), &hexlen
)) { 
 102                                 PrintAndLog("Invalid HEX value."); 
 105                                 PrintAndLog("Too many bytes.  Max %d bytes", sizeof(data
)); 
 108                                 PrintAndLog("Hex must have an even number of digits."); 
 116                         PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd
, cmdp
)); 
 126         if (errors 
|| cmdp 
== 0 ) return usage_sm_raw(); 
 130         UsbCommand c 
= {CMD_SMART_RAW
, {0, hexlen
, 0}}; 
 132         if (active 
|| active_select
) { 
 133                 c
.arg
[0] |= SC_CONNECT
; 
 135                         c
.arg
[0] |= SC_NO_SELECT
; 
 142         memcpy(c
.d
.asBytes
, data
, hexlen 
); 
 143         clearCommandBuffer(); 
 146         // reading response from smart card 
 149                 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 2500)) { 
 150                         PrintAndLog("smart card response failed"); 
 153                 uint32_t datalen 
= resp
.arg
[0]; 
 156                         PrintAndLog("smart card response failed"); 
 160                 PrintAndLog("received %i bytes", datalen
); 
 165                 uint8_t *data 
= resp
.d
.asBytes
; 
 171                                 PrintAndLog("%02x %02x | %s", data
[datalen 
- 2], data
[datalen 
- 1], GetAPDUCodeDescription(data
[datalen 
- 2], data
[datalen 
- 1]));  
 174                                 TLVPrintFromBuffer(data
, datalen 
- 2); 
 177                         PrintAndLog("%s", sprint_hex(data
,  datalen
));  
 183 int CmdSmartUpgrade(const char *Cmd
) { 
 185         PrintAndLog("WARNING - Smartcard socket firmware upgrade."); 
 186         PrintAndLog("Dangerous command, do wrong and you will brick the smart card socket"); 
 189         char filename
[FILE_PATH_SIZE
] = {0}; 
 193         while (param_getchar(Cmd
, cmdp
) != 0x00 && !errors
) { 
 194                 switch (tolower(param_getchar(Cmd
, cmdp
))) { 
 196                         //File handling and reading 
 197                         if ( param_getstr(Cmd
, cmdp
+1, filename
, FILE_PATH_SIZE
) >= FILE_PATH_SIZE 
) { 
 198                                 PrintAndLog("Filename too long"); 
 205                         return usage_sm_upgrade(); 
 207                         PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd
, cmdp
)); 
 214         if (errors 
|| cmdp 
== 0 ) return usage_sm_upgrade(); 
 217         f 
= fopen(filename
, "rb"); 
 219                 PrintAndLog("File: %s: not found or locked.", filename
); 
 223         // get filesize in order to malloc memory 
 224         fseek(f
, 0, SEEK_END
); 
 225         long fsize 
= ftell(f
); 
 226         fseek(f
, 0, SEEK_SET
); 
 229                 PrintAndLog("error, when getting filesize"); 
 234         uint8_t *dump 
= calloc(fsize
, sizeof(uint8_t)); 
 236                 PrintAndLog("error, cannot allocate memory "); 
 241         size_t bytes_read 
= fread(dump
, 1, fsize
, f
); 
 245         PrintAndLog("Smartcard socket firmware uploading to PM3"); 
 248         uint32_t bytes_sent 
= 0; 
 249         uint32_t bytes_remaining 
= bytes_read
; 
 251         while (bytes_remaining 
> 0){ 
 252                 uint32_t bytes_in_packet 
= MIN(USB_CMD_DATA_SIZE
, bytes_remaining
); 
 253                 UsbCommand c 
= {CMD_SMART_UPLOAD
, {index 
+ bytes_sent
, bytes_in_packet
, 0}}; 
 255                 // Fill usb bytes with 0xFF 
 256                 memset(c
.d
.asBytes
, 0xFF, USB_CMD_DATA_SIZE
); 
 257                 memcpy(c
.d
.asBytes
, dump 
+ bytes_sent
, bytes_in_packet
); 
 258                 clearCommandBuffer(); 
 260                 if ( !WaitForResponseTimeout(CMD_ACK
, NULL
, 2000) ) { 
 261                         PrintAndLog("timeout while waiting for reply."); 
 266                 bytes_remaining 
-= bytes_in_packet
; 
 267                 bytes_sent 
+= bytes_in_packet
; 
 268                 printf("."); fflush(stdout
); 
 272         PrintAndLog("Smartcard socket firmware updating,  don\'t turn off your PM3!"); 
 274         // trigger the firmware upgrade 
 275         UsbCommand c 
= {CMD_SMART_UPGRADE
, {bytes_read
, 0, 0}}; 
 276         clearCommandBuffer(); 
 279         if ( !WaitForResponseTimeout(CMD_ACK
, &resp
, 2500) ) { 
 280                 PrintAndLog("timeout while waiting for reply."); 
 283         if ( (resp
.arg
[0] && 0xFF ) ) 
 284                 PrintAndLog("Smartcard socket firmware upgraded successful"); 
 286                 PrintAndLog("Smartcard socket firmware updating failed"); 
 290 int CmdSmartInfo(const char *Cmd
){ 
 292         bool errors 
= false, silent 
= false; 
 294         while (param_getchar(Cmd
, cmdp
) != 0x00 && !errors
) { 
 295                 switch (tolower(param_getchar(Cmd
, cmdp
))) { 
 296                 case 'h': return usage_sm_info(); 
 301                         PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd
, cmdp
)); 
 309         if (errors 
) return usage_sm_info(); 
 311         UsbCommand c 
= {CMD_SMART_ATR
, {0, 0, 0}}; 
 312         clearCommandBuffer(); 
 315         if ( !WaitForResponseTimeout(CMD_ACK
, &resp
, 2500) ) { 
 316                 if (!silent
) PrintAndLog("smart card select failed"); 
 320         uint8_t isok 
= resp
.arg
[0] & 0xFF; 
 322                 if (!silent
) PrintAndLog("smart card select failed"); 
 326         smart_card_atr_t card
; 
 327         memcpy(&card
, (smart_card_atr_t 
*)resp
.d
.asBytes
, sizeof(smart_card_atr_t
)); 
 330         PrintAndLog("\n--- Smartcard Information ---------"); 
 331         PrintAndLog("-------------------------------------------------------------"); 
 332         PrintAndLog("ISO76183 ATR : %s", sprint_hex(card
.atr
, card
.atr_len
)); 
 333         PrintAndLog("look up ATR"); 
 334         PrintAndLog("http://smartcard-atr.appspot.com/parse?ATR=%s", sprint_hex_inrow(card
.atr
, card
.atr_len
) ); 
 338 int CmdSmartReader(const char *Cmd
){ 
 340         bool errors 
= false, silent 
= false; 
 342         while (param_getchar(Cmd
, cmdp
) != 0x00 && !errors
) { 
 343                 switch (tolower(param_getchar(Cmd
, cmdp
))) { 
 344                 case 'h': return usage_sm_reader(); 
 349                         PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd
, cmdp
)); 
 357         if (errors 
) return usage_sm_reader(); 
 359         UsbCommand c 
= {CMD_SMART_ATR
, {0, 0, 0}}; 
 360         clearCommandBuffer(); 
 363         if ( !WaitForResponseTimeout(CMD_ACK
, &resp
, 2500) ) { 
 364                 if (!silent
) PrintAndLog("smart card select failed"); 
 368         uint8_t isok 
= resp
.arg
[0] & 0xFF; 
 370                 if (!silent
) PrintAndLog("smart card select failed"); 
 373         smart_card_atr_t card
; 
 374         memcpy(&card
, (smart_card_atr_t 
*)resp
.d
.asBytes
, sizeof(smart_card_atr_t
)); 
 375         PrintAndLog("ISO7816-3 ATR : %s", sprint_hex(card
.atr
, card
.atr_len
));   
 379 int CmdSmartSetClock(const char *Cmd
){ 
 383         while (param_getchar(Cmd
, cmdp
) != 0x00 && !errors
) { 
 384                 switch (tolower(param_getchar(Cmd
, cmdp
))) { 
 385                 case 'h': return usage_sm_setclock(); 
 387                         clock 
= param_get8ex(Cmd
, cmdp
+1, 2, 10); 
 394                         PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd
, cmdp
)); 
 401         if (errors 
|| cmdp 
== 0) return usage_sm_setclock(); 
 403         UsbCommand c 
= {CMD_SMART_SETCLOCK
, {clock
, 0, 0}}; 
 404         clearCommandBuffer(); 
 407         if ( !WaitForResponseTimeout(CMD_ACK
, &resp
, 2500) ) { 
 408                 PrintAndLog("smart card select failed"); 
 412         uint8_t isok 
= resp
.arg
[0] & 0xFF; 
 414                 PrintAndLog("smart card set clock failed"); 
 420                         PrintAndLog("Clock changed to 16mhz giving 10800 baudrate"); 
 423                         PrintAndLog("Clock changed to 8mhz giving 21600 baudrate"); 
 426                         PrintAndLog("Clock changed to 4mhz giving 86400 baudrate"); 
 436 void annotateIso7816(char *exp
, size_t size
, uint8_t* cmd
, uint8_t cmdsize
){ 
 438         if ( (cmd
[0] & 0xC0) && (cmdsize 
== 3) ) { 
 439                 switch ( (cmd
[0] & 0x3f)  ) { 
 440                         case 0x00 : snprintf(exp
, size
, "S-block RESYNCH req"); break; 
 441                         case 0x20 : snprintf(exp
, size
, "S-block RESYNCH resp"); break; 
 442                         case 0x01 : snprintf(exp
, size
, "S-block IFS req"); break; 
 443                         case 0x21 : snprintf(exp
, size
, "S-block IFS resp"); break; 
 444                         case 0x02 : snprintf(exp
, size
, "S-block ABORT req"); break; 
 445                         case 0x22 : snprintf(exp
, size
, "S-block ABORT resp"); break; 
 446                         case 0x03 : snprintf(exp
, size
, "S-block WTX reqt"); break; 
 447                         case 0x23 : snprintf(exp
, size
, "S-block WTX resp"); break; 
 448                         default   : snprintf(exp
, size
, "S-block"); break; 
 452         else if ( ((cmd
[0] & 0xD0) == 0x80) && ( cmdsize 
> 2) ) { 
 453                 if ( (cmd
[0] & 0x10) == 0 )  
 454                         snprintf(exp
, size
, "R-block ACK"); 
 456                         snprintf(exp
, size
, "R-block NACK"); 
 461                 int pos 
= (cmd
[0] == 2 ||  cmd
[0] == 3) ? 2 : 3; 
 462                 switch ( cmd
[pos
] ) { 
 463                         case ISO7816_READ_BINARY             
:snprintf(exp
, size
, "READ BIN");break; 
 464                         case ISO7816_WRITE_BINARY            
:snprintf(exp
, size
, "WRITE BIN");break; 
 465                         case ISO7816_UPDATE_BINARY           
:snprintf(exp
, size
, "UPDATE BIN");break; 
 466                         case ISO7816_ERASE_BINARY            
:snprintf(exp
, size
, "ERASE BIN");break; 
 467                         case ISO7816_READ_RECORDS            
:snprintf(exp
, size
, "READ RECORDS");break; 
 468                         case ISO7816_WRITE_RECORDS           
:snprintf(exp
, size
, "WRITE RECORDS");break; 
 469                         case ISO7816_APPEND_RECORD           
:snprintf(exp
, size
, "APPEND RECORD");break; 
 470                         case ISO7816_UPDATE_RECORD           
:snprintf(exp
, size
, "UPDATE RECORD");break; 
 471                         case ISO7816_GET_DATA                
:snprintf(exp
, size
, "GET DATA");break; 
 472                         case ISO7816_PUT_DATA                
:snprintf(exp
, size
, "PUT DATA");break; 
 473                         case ISO7816_SELECT_FILE             
:snprintf(exp
, size
, "SELECT FILE");break; 
 474                         case ISO7816_VERIFY                  
:snprintf(exp
, size
, "VERIFY");break; 
 475                         case ISO7816_INTERNAL_AUTHENTICATION 
:snprintf(exp
, size
, "INTERNAL AUTH");break; 
 476                         case ISO7816_EXTERNAL_AUTHENTICATION 
:snprintf(exp
, size
, "EXTERNAL AUTH");break; 
 477                         case ISO7816_GET_CHALLENGE           
:snprintf(exp
, size
, "GET CHALLENGE");break; 
 478                         case ISO7816_MANAGE_CHANNEL          
:snprintf(exp
, size
, "MANAGE CHANNEL");break; 
 479                         default                              :snprintf(exp
, size
, "?"); break; 
 485 uint16_t printScTraceLine(uint16_t tracepos
, uint16_t traceLen
, uint8_t *trace
) { 
 487         if (tracepos 
+ sizeof(uint32_t) + sizeof(uint16_t) + sizeof(uint16_t) > traceLen
) return traceLen
; 
 490         uint16_t data_len
, parity_len
; 
 491         uint32_t duration
, timestamp
, first_timestamp
, EndOfTransmissionTimestamp
; 
 492         char explanation
[30] = {0}; 
 494         first_timestamp 
= *((uint32_t *)(trace
)); 
 495         timestamp 
= *((uint32_t *)(trace 
+ tracepos
)); 
 498         duration 
= *((uint16_t *)(trace 
+ tracepos
)); 
 501         data_len 
= *((uint16_t *)(trace 
+ tracepos
)); 
 504         if (data_len 
& 0x8000) { 
 511         parity_len 
= (data_len
-1)/8 + 1; 
 512         if (tracepos 
+ data_len 
+ parity_len 
> traceLen
) { 
 515         uint8_t *frame 
= trace 
+ tracepos
; 
 516         tracepos 
+= data_len
; 
 517         //uint8_t *parityBytes = trace + tracepos; 
 518         tracepos 
+= parity_len
; 
 520         //--- Draw the data column 
 523         if (data_len 
== 0 ) { 
 524                 sprintf(line
[0],"<empty trace - possible error>"); 
 528         for (int j 
= 0; j 
< data_len 
&& j
/18 < 18; j
++) { 
 529                 snprintf(line
[j
/18]+(( j 
% 18) * 4),110, "%02x  ", frame
[j
]); 
 532         EndOfTransmissionTimestamp 
= timestamp 
+ duration
; 
 534         annotateIso7816(explanation
,sizeof(explanation
),frame
,data_len
); 
 536         int num_lines 
= MIN((data_len 
- 1)/18 + 1, 18); 
 537         for (int j 
= 0; j 
< num_lines 
; j
++) { 
 539                         PrintAndLog(" %10u | %10u | %s |%-72s | %s| %s", 
 540                                 (timestamp 
- first_timestamp
), 
 541                                 (EndOfTransmissionTimestamp 
- first_timestamp
), 
 542                                 (isResponse 
? "Tag" : "Rdr"), 
 545                                 (j 
== num_lines
-1) ? explanation 
: ""); 
 547                         PrintAndLog("            |            |     |%-72s | %s| %s", 
 550                                 (j 
== num_lines
-1) ? explanation 
: ""); 
 555         if (tracepos 
+ sizeof(uint32_t) + sizeof(uint16_t) + sizeof(uint16_t) >= traceLen
) return traceLen
; 
 560 int ScTraceList(const char *Cmd
) { 
 561         bool loadFromFile 
= false; 
 562         bool saveToFile 
= false; 
 564         char filename
[FILE_PATH_SIZE
] = {0}; 
 566         // parse command line 
 567         param_getstr(Cmd
, 0, type
, sizeof(type
)); 
 568         param_getstr(Cmd
, 1, filename
, sizeof(filename
)); 
 576                 if (strcmp(type
, "s") == 0) { 
 578                 } else if (strcmp(type
,"l") == 0) { 
 583         if ((loadFromFile 
|| saveToFile
) && strlen(filename
) == 0) { 
 587         if (loadFromFile 
&& saveToFile
) { 
 592                 PrintAndLog("List or save protocol data."); 
 593                 PrintAndLog("Usage:  sc list [l <filename>]"); 
 594                 PrintAndLog("        sc list [s <filename>]"); 
 595                 PrintAndLog("    l      - load data from file instead of trace buffer"); 
 596                 PrintAndLog("    s      - save data to file"); 
 598                 PrintAndLog("example: sc list"); 
 599                 PrintAndLog("example: sc list save myCardTrace.trc"); 
 600                 PrintAndLog("example: sc list l myCardTrace.trc"); 
 605         uint32_t tracepos 
= 0; 
 606         uint32_t traceLen 
= 0; 
 609                 #define TRACE_CHUNK_SIZE (1<<16)    // 64K to start with. Will be enough for BigBuf and some room for future extensions 
 610                 FILE *tracefile 
= NULL
; 
 612                 trace 
= malloc(TRACE_CHUNK_SIZE
); 
 614                         PrintAndLog("Cannot allocate memory for trace"); 
 617                 if ((tracefile 
= fopen(filename
,"rb")) == NULL
) {  
 618                         PrintAndLog("Could not open file %s", filename
); 
 622                 while (!feof(tracefile
)) { 
 623                         bytes_read 
= fread(trace
+traceLen
, 1, TRACE_CHUNK_SIZE
, tracefile
); 
 624                         traceLen 
+= bytes_read
; 
 625                         if (!feof(tracefile
)) { 
 626                                 uint8_t *p 
= realloc(trace
, traceLen 
+ TRACE_CHUNK_SIZE
); 
 628                                         PrintAndLog("Cannot allocate memory for trace"); 
 638                 trace 
= malloc(USB_CMD_DATA_SIZE
); 
 639                 // Query for the size of the trace 
 641                 GetFromBigBuf(trace
, USB_CMD_DATA_SIZE
, 0, &response
, -1, false); 
 642                 traceLen 
= response
.arg
[2]; 
 643                 if (traceLen 
> USB_CMD_DATA_SIZE
) { 
 644                         uint8_t *p 
= realloc(trace
, traceLen
); 
 646                                 PrintAndLog("Cannot allocate memory for trace"); 
 651                         GetFromBigBuf(trace
, traceLen
, 0, NULL
, -1, false); 
 656                 FILE *tracefile 
= NULL
; 
 657                 if ((tracefile 
= fopen(filename
,"wb")) == NULL
) {  
 658                         PrintAndLog("Could not create file %s", filename
); 
 661                 fwrite(trace
, 1, traceLen
, tracefile
); 
 662                 PrintAndLog("Recorded Activity (TraceLen = %d bytes) written to file %s", traceLen
, filename
); 
 665                 PrintAndLog("Recorded Activity (TraceLen = %d bytes)", traceLen
); 
 667                 PrintAndLog("Start = Start of Start Bit, End = End of last modulation. Src = Source of Transfer"); 
 669                 PrintAndLog("      Start |        End | Src | Data (! denotes parity error)                                           | CRC | Annotation         |"); 
 670                 PrintAndLog("------------|------------|-----|-------------------------------------------------------------------------|-----|--------------------|"); 
 672                 while(tracepos 
< traceLen
) 
 674                         tracepos 
= printScTraceLine(tracepos
, traceLen
, trace
); 
 682 int CmdSmartList(const char *Cmd
) { 
 687 static command_t CommandTable
[] = { 
 688         {"help",    CmdHelp
,          1, "This help"}, 
 689         {"list",    CmdSmartList
,     0, "List ISO 7816 history"}, 
 690         {"info",    CmdSmartInfo
,     1, "Tag information [rdv40]"}, 
 691         {"reader",  CmdSmartReader
,   1, "Act like an IS07816 reader [rdv40]"}, 
 692         {"raw",     CmdSmartRaw
,      1, "Send raw hex data to tag [rdv40]"}, 
 693         {"upgrade", CmdSmartUpgrade
,  1, "Upgrade firmware [rdv40]"}, 
 694         {"setclock",CmdSmartSetClock
, 1, "Set clock speed"}, 
 695         {NULL
, NULL
, 0, NULL
} 
 698 int CmdSmartcard(const char *Cmd
) { 
 699         clearCommandBuffer(); 
 700         CmdsParse(CommandTable
, Cmd
); 
 704 int CmdHelp(const char *Cmd
) { 
 705         CmdsHelp(CommandTable
);