| 1 | //Peter Fillmore - 2014 |
| 2 | // |
| 3 | //-------------------------------------------------------------------------------- |
| 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 |
| 6 | // the license. |
| 7 | //-------------------------------------------------------------------------------- |
| 8 | //-------------------------------------------------------------------------------- |
| 9 | //Routines to support EMV transactions |
| 10 | //-------------------------------------------------------------------------------- |
| 11 | |
| 12 | #include "mifare.h" |
| 13 | #include "iso14443a.h" |
| 14 | #include "emvutil.h" |
| 15 | #include "emvcmd.h" |
| 16 | #include "apps.h" |
| 17 | #include "emvdataels.h" |
| 18 | |
| 19 | static emvtags currentcard; //use to hold emv tags for the reader/card during communications |
| 20 | static tUart Uart; |
| 21 | |
| 22 | // The FPGA will report its internal sending delay in |
| 23 | uint16_t FpgaSendQueueDelay; |
| 24 | //variables used for timing purposes: |
| 25 | //these are in ssp_clk cycles: |
| 26 | //static uint32_t NextTransferTime; |
| 27 | static uint32_t LastTimeProxToAirStart; |
| 28 | //static uint32_t LastProxToAirDuration; |
| 29 | |
| 30 | //load individual tag into current card |
| 31 | void EMVloadvalue(uint32_t tag, uint8_t *datain){ |
| 32 | //Dbprintf("TAG=%i\n", tag); |
| 33 | //Dbprintf("DATA=%s\n", datain); |
| 34 | emv_settag(tag, datain, ¤tcard); |
| 35 | } |
| 36 | |
| 37 | void EMVReadRecord(uint8_t arg0, uint8_t arg1,emvtags *currentcard) |
| 38 | { |
| 39 | uint8_t record = arg0; |
| 40 | uint8_t sfi = arg1 & 0x0F; //convert arg1 to number |
| 41 | uint8_t receivedAnswer[MAX_FRAME_SIZE]; |
| 42 | |
| 43 | //uint8_t receivedAnswerPar[MAX_PARITY_SIZE]; |
| 44 | |
| 45 | //variables |
| 46 | tlvtag inputtag; //create the tag structure |
| 47 | //perform read |
| 48 | //write the result to the provided card |
| 49 | if(!emv_readrecord(record,sfi,receivedAnswer)) { |
| 50 | if(EMV_DBGLEVEL >= 1) Dbprintf("readrecord failed"); |
| 51 | } |
| 52 | if(*(receivedAnswer+1) == 0x70){ |
| 53 | decode_ber_tlv_item(receivedAnswer+1, &inputtag); |
| 54 | emv_decode_field(inputtag.value, inputtag.valuelength, currentcard); |
| 55 | } |
| 56 | else |
| 57 | { |
| 58 | if(EMV_DBGLEVEL >= 1) |
| 59 | Dbprintf("Record not found SFI=%i RECORD=%i", sfi, record); |
| 60 | } |
| 61 | return; |
| 62 | } |
| 63 | |
| 64 | void EMVSelectAID(uint8_t *AID, uint8_t AIDlen, emvtags* inputcard) |
| 65 | { |
| 66 | uint8_t receivedAnswer[MAX_FRAME_SIZE]; |
| 67 | //uint8_t receivedAnswerPar[MAX_PARITY_SIZE]; |
| 68 | |
| 69 | //variables |
| 70 | tlvtag inputtag; //create the tag structure |
| 71 | //perform select |
| 72 | if(!emv_select(AID, AIDlen, receivedAnswer)){ |
| 73 | if(EMV_DBGLEVEL >= 1) Dbprintf("AID Select failed"); |
| 74 | return; |
| 75 | } |
| 76 | //write the result to the provided card |
| 77 | if(*(receivedAnswer+1) == 0x6F){ |
| 78 | //decode the 6F template |
| 79 | decode_ber_tlv_item(receivedAnswer+1, &inputtag); |
| 80 | //store 84 and A5 tags |
| 81 | emv_decode_field(inputtag.value, inputtag.valuelength, ¤tcard); |
| 82 | //decode the A5 tag |
| 83 | if(currentcard.tag_A5_len > 0) |
| 84 | emv_decode_field(currentcard.tag_A5, currentcard.tag_A5_len, ¤tcard); |
| 85 | |
| 86 | //copy this result to the DFName |
| 87 | if(currentcard.tag_84_len == 0) |
| 88 | memcpy(currentcard.tag_DFName, currentcard.tag_84, currentcard.tag_84_len); |
| 89 | |
| 90 | //decode the BF0C result, assuming 1 directory entry for now |
| 91 | if(currentcard.tag_BF0C_len !=0){ |
| 92 | emv_decode_field(currentcard.tag_BF0C, currentcard.tag_BF0C_len, ¤tcard);} |
| 93 | //retrieve the AID, use the AID to decide what transaction flow to use |
| 94 | if(currentcard.tag_61_len !=0){ |
| 95 | emv_decode_field(currentcard.tag_61, currentcard.tag_61_len, ¤tcard);} |
| 96 | } |
| 97 | if(EMV_DBGLEVEL >= 2) |
| 98 | DbpString("SELECT AID COMPLETED"); |
| 99 | } |
| 100 | |
| 101 | int EMVGetProcessingOptions(uint8_t *PDOL, uint8_t PDOLlen, emvtags* inputcard) |
| 102 | { |
| 103 | uint8_t receivedAnswer[MAX_FRAME_SIZE]; |
| 104 | //uint8_t receivedAnswerPar[MAX_PARITY_SIZE]; |
| 105 | |
| 106 | //variables |
| 107 | tlvtag inputtag; //create the tag structure |
| 108 | //perform pdol |
| 109 | if(!emv_getprocessingoptions(PDOL, PDOLlen, receivedAnswer)){ |
| 110 | if(EMV_DBGLEVEL >= 1) Dbprintf("get processing options failed"); |
| 111 | return 0; |
| 112 | } |
| 113 | //write the result to the provided card |
| 114 | //FORMAT 1 received |
| 115 | if(receivedAnswer[1] == 0x80){ |
| 116 | //store AIP |
| 117 | //decode tag 80 |
| 118 | decode_ber_tlv_item(receivedAnswer+1, &inputtag); |
| 119 | memcpy(currentcard.tag_82, &inputtag.value, sizeof(currentcard.tag_82)); |
| 120 | memcpy(currentcard.tag_94, &inputtag.value[2], inputtag.valuelength - sizeof(currentcard.tag_82)); |
| 121 | currentcard.tag_94_len = inputtag.valuelength - sizeof(currentcard.tag_82); |
| 122 | } |
| 123 | else if(receivedAnswer[1] == 0x77){ |
| 124 | //decode the 77 template |
| 125 | decode_ber_tlv_item(receivedAnswer+1, &inputtag); |
| 126 | //store 82 and 94 tags (AIP, AFL) |
| 127 | emv_decode_field(inputtag.value, inputtag.valuelength, ¤tcard); |
| 128 | } |
| 129 | if(EMV_DBGLEVEL >= 2) |
| 130 | DbpString("GET PROCESSING OPTIONS COMPLETE"); |
| 131 | return 1; |
| 132 | } |
| 133 | |
| 134 | int EMVGetChallenge(emvtags* inputcard) |
| 135 | { |
| 136 | uint8_t receivedAnswer[MAX_FRAME_SIZE]; |
| 137 | //uint8_t receivedAnswerPar[MAX_PARITY_SIZE]; |
| 138 | //variables |
| 139 | //tlvtag inputtag; //create the tag structure |
| 140 | //perform select |
| 141 | if(!emv_getchallenge(receivedAnswer)){ |
| 142 | if(EMV_DBGLEVEL >= 1) Dbprintf("get processing options failed"); |
| 143 | return 1; |
| 144 | } |
| 145 | return 0; |
| 146 | } |
| 147 | |
| 148 | int EMVGenerateAC(uint8_t refcontrol, emvtags* inputcard) |
| 149 | { |
| 150 | uint8_t receivedAnswer[MAX_FRAME_SIZE]; |
| 151 | uint8_t cdolcommand[MAX_FRAME_SIZE]; |
| 152 | uint8_t cdolcommandlen = 0; |
| 153 | tlvtag temptag; |
| 154 | |
| 155 | //uint8_t receivedAnswerPar[MAX_PARITY_SIZE]; |
| 156 | if(currentcard.tag_8C_len > 0) { |
| 157 | emv_generateDOL(currentcard.tag_8C, currentcard.tag_8C_len, ¤tcard, cdolcommand, &cdolcommandlen); } |
| 158 | else{ |
| 159 | //cdolcommand = NULL; //cdol val is null |
| 160 | cdolcommandlen = 0; |
| 161 | } |
| 162 | //variables |
| 163 | //tlvtag inputtag; //create the tag structure |
| 164 | //perform select |
| 165 | if(!emv_generateAC(refcontrol, cdolcommand, cdolcommandlen,receivedAnswer)){ |
| 166 | if(EMV_DBGLEVEL >= 1) Dbprintf("get processing options failed"); |
| 167 | return 1; |
| 168 | } |
| 169 | if(receivedAnswer[2] == 0x77) //format 2 data field returned |
| 170 | { |
| 171 | decode_ber_tlv_item(&receivedAnswer[2], &temptag); |
| 172 | emv_decode_field(temptag.value, temptag.valuelength, ¤tcard); |
| 173 | } |
| 174 | |
| 175 | return 0; |
| 176 | } |
| 177 | |
| 178 | //function to perform paywave transaction |
| 179 | //takes in TTQ, amount authorised, unpredicable number and transaction currency code |
| 180 | int EMV_PaywaveTransaction() |
| 181 | { |
| 182 | uint8_t cardMode = 0; |
| 183 | //determine mode of transaction from TTQ |
| 184 | if((currentcard.tag_9F66[0] & 0x40) == 0x40) { |
| 185 | cardMode = VISA_EMV; |
| 186 | } |
| 187 | else if((currentcard.tag_9F66[0] & 0x20) == 0x20) { |
| 188 | cardMode = VISA_FDDA; |
| 189 | } |
| 190 | else if((currentcard.tag_9F66[0] & 0x80) == 0x80) { |
| 191 | if((currentcard.tag_9F66[1] & 0x80) == 1) { //CVN17 |
| 192 | cardMode = VISA_CVN17; |
| 193 | } |
| 194 | else{ |
| 195 | cardMode = VISA_DCVV; |
| 196 | } |
| 197 | } |
| 198 | |
| 199 | EMVSelectAID(currentcard.tag_4F,currentcard.tag_4F_len, ¤tcard); //perform second AID command |
| 200 | |
| 201 | //get PDOL |
| 202 | uint8_t pdolcommand[20]; //20 byte buffer for pdol data |
| 203 | uint8_t pdolcommandlen = 0; |
| 204 | if(currentcard.tag_9F38_len > 0) { |
| 205 | emv_generateDOL(currentcard.tag_9F38, currentcard.tag_9F38_len, ¤tcard, pdolcommand, &pdolcommandlen); |
| 206 | } |
| 207 | Dbhexdump(pdolcommandlen, pdolcommand,false); |
| 208 | |
| 209 | if(!EMVGetProcessingOptions(pdolcommand,pdolcommandlen, ¤tcard)) { |
| 210 | if(EMV_DBGLEVEL >= 1) Dbprintf("PDOL failed"); |
| 211 | return 1; |
| 212 | } |
| 213 | |
| 214 | Dbprintf("AFL="); |
| 215 | Dbhexdump(currentcard.tag_94_len, currentcard.tag_94,false); |
| 216 | Dbprintf("AIP="); |
| 217 | Dbhexdump(2, currentcard.tag_82, false); |
| 218 | emv_decodeAIP(currentcard.tag_82); |
| 219 | // |
| 220 | // //decode the AFL list and read records |
| 221 | uint8_t i = 0; |
| 222 | uint8_t sfi = 0; |
| 223 | uint8_t recordstart = 0; |
| 224 | uint8_t recordend = 0; |
| 225 | if(currentcard.tag_94_len > 0){ |
| 226 | while( i < currentcard.tag_94_len){ |
| 227 | sfi = (currentcard.tag_94[i++] & 0xF8) >> 3; |
| 228 | recordstart = currentcard.tag_94[i++]; |
| 229 | recordend = currentcard.tag_94[i++]; |
| 230 | for(int j=recordstart; j<(recordend+1); j++){ |
| 231 | //read records |
| 232 | EMVReadRecord(j,sfi, ¤tcard); |
| 233 | //while(responsebuffer[0] == 0xF2) { |
| 234 | // EMVReadRecord(j,sfi, ¤tcard); |
| 235 | //} |
| 236 | } |
| 237 | i++; |
| 238 | } |
| 239 | } |
| 240 | else { |
| 241 | EMVReadRecord(1,1,¤tcard); |
| 242 | EMVReadRecord(1,2,¤tcard); |
| 243 | EMVReadRecord(1,3,¤tcard); |
| 244 | EMVReadRecord(2,1,¤tcard); |
| 245 | EMVReadRecord(2,2,¤tcard); |
| 246 | EMVReadRecord(2,3,¤tcard); |
| 247 | EMVReadRecord(3,1,¤tcard); |
| 248 | EMVReadRecord(3,3,¤tcard); |
| 249 | EMVReadRecord(4,2,¤tcard); |
| 250 | } |
| 251 | //EMVGetChallenge(¤tcard); |
| 252 | //memcpy(currentcard.tag_9F4C,&responsebuffer[1],8); // ICC UN |
| 253 | EMVGenerateAC(0x81,¤tcard); |
| 254 | |
| 255 | Dbprintf("CARDMODE=%i",cardMode); |
| 256 | return 0; |
| 257 | } |
| 258 | |
| 259 | |
| 260 | int EMV_PaypassTransaction() |
| 261 | { |
| 262 | //uint8_t *responsebuffer = emv_get_bigbufptr(); |
| 263 | //tlvtag temptag; //buffer for decoded tags |
| 264 | //get the current block counter |
| 265 | //select the AID (Mastercard |
| 266 | EMVSelectAID(currentcard.tag_4F,currentcard.tag_4F_len, ¤tcard); |
| 267 | |
| 268 | //get PDOL |
| 269 | uint8_t pdolcommand[20]; //20 byte buffer for pdol data |
| 270 | uint8_t pdolcommandlen = 0; |
| 271 | if(currentcard.tag_9F38_len > 0) { |
| 272 | emv_generateDOL(currentcard.tag_9F38, currentcard.tag_9F38_len, ¤tcard, pdolcommand, &pdolcommandlen); |
| 273 | } |
| 274 | if(EMVGetProcessingOptions(pdolcommand,pdolcommandlen, ¤tcard)) { |
| 275 | if(EMV_DBGLEVEL >= 1) Dbprintf("PDOL failed"); |
| 276 | return 1; |
| 277 | } |
| 278 | |
| 279 | Dbprintf("AFL="); |
| 280 | Dbhexdump(currentcard.tag_94_len, currentcard.tag_94,false); |
| 281 | Dbprintf("AIP="); |
| 282 | Dbhexdump(2, currentcard.tag_82, false); |
| 283 | emv_decodeAIP(currentcard.tag_82); |
| 284 | |
| 285 | //decode the AFL list and read records |
| 286 | uint8_t i = 0; |
| 287 | uint8_t sfi = 0; |
| 288 | uint8_t recordstart = 0; |
| 289 | uint8_t recordend = 0; |
| 290 | |
| 291 | while( i< currentcard.tag_94_len){ |
| 292 | sfi = (currentcard.tag_94[i++] & 0xF8) >> 3; |
| 293 | recordstart = currentcard.tag_94[i++]; |
| 294 | recordend = currentcard.tag_94[i++]; |
| 295 | for(int j=recordstart; j<(recordend+1); j++){ |
| 296 | //read records |
| 297 | EMVReadRecord(j,sfi, ¤tcard); |
| 298 | //while(responsebuffer[0] == 0xF2) { |
| 299 | // EMVReadRecord(j,sfi, ¤tcard); |
| 300 | //} |
| 301 | } |
| 302 | i++; |
| 303 | } |
| 304 | /* get ICC dynamic data */ |
| 305 | if((currentcard.tag_82[0] & AIP_CDA_SUPPORTED) == AIP_CDA_SUPPORTED) |
| 306 | { |
| 307 | //DDA supported, so perform GENERATE AC |
| 308 | //generate the iCC UN |
| 309 | EMVGetChallenge(¤tcard); |
| 310 | //memcpy(currentcard.tag_9F4C,&responsebuffer[1],8); // ICC UN |
| 311 | EMVGenerateAC(0x80,¤tcard); |
| 312 | |
| 313 | |
| 314 | //generate AC2 |
| 315 | //if(currentcard.tag_8D_len > 0) { |
| 316 | // emv_generateDOL(currentcard.tag_8D, currentcard.tag_8D_len, ¤tcard, cdolcommand, &cdolcommandlen); } |
| 317 | //else{ |
| 318 | // //cdolcommand = NULL; //cdol val is null |
| 319 | // cdolcommandlen = 0; |
| 320 | //} |
| 321 | //emv_generateAC(0x80, cdolcommand,cdolcommandlen, ¤tcard); |
| 322 | |
| 323 | //if(responsebuffer[1] == 0x77) //format 2 data field returned |
| 324 | //{ |
| 325 | // decode_ber_tlv_item(&responsebuffer[1], &temptag); |
| 326 | // emv_decode_field(temptag.value, temptag.valuelength, ¤tcard); |
| 327 | //} |
| 328 | } |
| 329 | //generate cryptographic checksum |
| 330 | //uint8_t udol[4] = {0x00,0x00,0x00,0x00}; |
| 331 | //emv_computecryptogram(udol, sizeof(udol)); |
| 332 | //if(responsebuffer[1] == 0x77) //format 2 data field returned |
| 333 | //{ |
| 334 | // decode_ber_tlv_item(&responsebuffer[1], &temptag); |
| 335 | // emv_decode_field(temptag.value, temptag.valuelength, ¤tcard); |
| 336 | //} |
| 337 | return 0; |
| 338 | } |
| 339 | |
| 340 | void EMVTransaction() |
| 341 | { |
| 342 | //params |
| 343 | uint8_t uid[10] = {0x00}; |
| 344 | uint32_t cuid = 0; |
| 345 | |
| 346 | //setup stuff |
| 347 | BigBuf_free(); BigBuf_Clear_ext(false); |
| 348 | clear_trace(); |
| 349 | set_tracing(TRUE); |
| 350 | |
| 351 | LED_A_ON(); |
| 352 | LED_B_OFF(); |
| 353 | LED_C_OFF(); |
| 354 | |
| 355 | iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); |
| 356 | while(true) { |
| 357 | if(!iso14443a_select_card(uid,NULL,&cuid)) { |
| 358 | if(EMV_DBGLEVEL >= 1) Dbprintf("Can't select card"); |
| 359 | break; |
| 360 | } |
| 361 | //selectPPSE |
| 362 | EMVSelectAID((uint8_t *)DF_PSE, 14, ¤tcard); //hard coded len |
| 363 | //get response |
| 364 | if (!memcmp(currentcard.tag_4F, AID_MASTERCARD, sizeof(AID_MASTERCARD))){ |
| 365 | Dbprintf("Mastercard Paypass Card Detected"); |
| 366 | EMV_PaypassTransaction(); |
| 367 | } |
| 368 | else if (!memcmp(currentcard.tag_4F, AID_VISA, sizeof(AID_VISA))){ |
| 369 | Dbprintf("VISA Paywave Card Detected"); |
| 370 | EMV_PaywaveTransaction(); |
| 371 | } |
| 372 | //TODO: add other card schemes like AMEX, JCB, China Unionpay etc |
| 373 | break; |
| 374 | } |
| 375 | if (EMV_DBGLEVEL >= 2) DbpString("EMV TRANSACTION FINISHED"); |
| 376 | //finish up |
| 377 | FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); |
| 378 | LEDsoff(); |
| 379 | } |
| 380 | |
| 381 | void EMVdumpcard(void){ |
| 382 | dumpCard(¤tcard); |
| 383 | } |
| 384 | |
| 385 | //SIMULATOR CODE |
| 386 | //----------------------------------------------------------------------------- |
| 387 | // Main loop of simulated tag: receive commands from reader, decide what |
| 388 | // response to send, and send it. |
| 389 | //----------------------------------------------------------------------------- |
| 390 | void SimulateEMVcard() |
| 391 | { |
| 392 | //uint8_t sak; //select ACKnowledge |
| 393 | uint16_t readerPacketLen = 64; //reader packet length - provided by RATS, default to 64 bytes if RATS not supported |
| 394 | |
| 395 | // The first response contains the ATQA (note: bytes are transmitted in reverse order). |
| 396 | //uint8_t atqapacket[2]; |
| 397 | |
| 398 | // The second response contains the (mandatory) first 24 bits of the UID |
| 399 | uint8_t uid0packet[5] = {0x00}; |
| 400 | memcpy(uid0packet, currentcard.UID, sizeof(uid0packet)); |
| 401 | // Check if the uid uses the (optional) part |
| 402 | uint8_t uid1packet[5] = {0x00}; |
| 403 | memcpy(uid1packet, currentcard.UID, sizeof(uid1packet)); |
| 404 | |
| 405 | // Calculate the BitCountCheck (BCC) for the first 4 bytes of the UID. |
| 406 | uid0packet[4] = uid0packet[0] ^ uid0packet[1] ^ uid0packet[2] ^ uid0packet[3]; |
| 407 | |
| 408 | // Prepare the mandatory SAK (for 4 and 7 byte UID) |
| 409 | uint8_t sak0packet[3] = {0x00}; |
| 410 | memcpy(sak0packet,¤tcard.SAK1,1); |
| 411 | ComputeCrc14443(CRC_14443_A, sak0packet, 1, &sak0packet[1], &sak0packet[2]); |
| 412 | uint8_t sak1packet[3] = {0x00}; |
| 413 | memcpy(sak1packet,¤tcard.SAK2,1); |
| 414 | // Prepare the optional second SAK (for 7 byte UID), drop the cascade bit |
| 415 | ComputeCrc14443(CRC_14443_A, sak1packet, 1, &sak1packet[1], &sak1packet[2]); |
| 416 | |
| 417 | uint8_t authanspacket[] = { 0x00, 0x00, 0x00, 0x00 }; // Very random tag nonce |
| 418 | //setup response to ATS |
| 419 | uint8_t ratspacket[currentcard.ATS_len]; |
| 420 | memcpy(ratspacket,currentcard.ATS, currentcard.ATS_len); |
| 421 | AppendCrc14443a(ratspacket,sizeof(ratspacket)-2); |
| 422 | |
| 423 | // Format byte = 0x58: FSCI=0x08 (FSC=256), TA(1) and TC(1) present, |
| 424 | // TA(1) = 0x80: different divisors not supported, DR = 1, DS = 1 |
| 425 | // TB(1) = not present. Defaults: FWI = 4 (FWT = 256 * 16 * 2^4 * 1/fc = 4833us), SFGI = 0 (SFG = 256 * 16 * 2^0 * 1/fc = 302us) |
| 426 | // TC(1) = 0x02: CID supported, NAD not supported |
| 427 | //ComputeCrc14443(CRC_14443_A, response6, 4, &response6[4], &response6[5]); |
| 428 | |
| 429 | //Receive Acknowledge responses differ by PCB byte |
| 430 | uint8_t rack0packet[] = {0xa2,0x00,0x00}; |
| 431 | AppendCrc14443a(rack0packet,1); |
| 432 | uint8_t rack1packet[] = {0xa3,0x00,0x00}; |
| 433 | AppendCrc14443a(rack1packet,1); |
| 434 | //Negative Acknowledge |
| 435 | uint8_t rnak0packet[] = {0xb2,0x00,0x00}; |
| 436 | uint8_t rnak1packet[] = {0xb3,0x00,0x00}; |
| 437 | AppendCrc14443a(rnak0packet,1); |
| 438 | AppendCrc14443a(rnak1packet,1); |
| 439 | |
| 440 | //Protocol and parameter selection response, just say yes |
| 441 | uint8_t ppspacket[] = {0xd0,0x00,0x00}; |
| 442 | AppendCrc14443a(ppspacket,1); |
| 443 | |
| 444 | //hardcoded WTX packet - set to max time (49) |
| 445 | uint8_t wtxpacket[] ={0xf2,0x31,0x00,0x00}; |
| 446 | AppendCrc14443a(wtxpacket,2); |
| 447 | |
| 448 | //added additional responses for different readers, namely protocol parameter select and Receive acknowledments. - peter fillmore. |
| 449 | //added defininitions for predone responses to aid readability |
| 450 | #define ATR 0 |
| 451 | #define UID1 1 |
| 452 | #define UID2 2 |
| 453 | #define SELACK1 3 |
| 454 | #define SELACK2 4 |
| 455 | #define AUTH_ANS 5 |
| 456 | #define ATS 6 |
| 457 | #define RACK0 7 |
| 458 | #define RACK1 8 |
| 459 | #define RNAK0 9 |
| 460 | #define RNAK1 10 |
| 461 | #define PPSresponse 11 |
| 462 | #define WTX 12 |
| 463 | |
| 464 | #define TAG_RESPONSE_COUNT 13 |
| 465 | tag_response_info_t responses[TAG_RESPONSE_COUNT] = { |
| 466 | { .response = currentcard.ATQA, .response_n = sizeof(currentcard.ATQA) }, // Answer to request - respond with card type |
| 467 | { .response = uid0packet, .response_n = sizeof(uid0packet) }, // Anticollision cascade1 - respond with uid |
| 468 | { .response = uid1packet, .response_n = sizeof(uid1packet) }, // Anticollision cascade2 - respond with 2nd half of uid if asked |
| 469 | { .response = sak0packet, .response_n = sizeof(sak0packet) }, // Acknowledge select - cascade 1 |
| 470 | { .response = sak1packet, .response_n = sizeof(sak1packet) }, // Acknowledge select - cascade 2 |
| 471 | { .response = authanspacket, .response_n = sizeof(authanspacket) }, // Authentication answer (random nonce) |
| 472 | { .response = ratspacket, .response_n = sizeof(ratspacket) }, // dummy ATS (pseudo-ATR), answer to RATS |
| 473 | { .response = rack0packet, .response_n = sizeof(rack0packet) }, //R(ACK)0 |
| 474 | { .response = rack1packet, .response_n = sizeof(rack1packet) }, //R(ACK)0 |
| 475 | { .response = rnak0packet, .response_n = sizeof(rnak0packet) }, //R(NAK)0 |
| 476 | { .response = rnak1packet, .response_n = sizeof(rnak1packet) }, //R(NAK)1 |
| 477 | { .response = ppspacket, .response_n = sizeof(ppspacket)}, //PPS packet |
| 478 | { .response = wtxpacket, .response_n = sizeof(wtxpacket)}, //WTX packet |
| 479 | }; |
| 480 | |
| 481 | //calculated length of predone responses |
| 482 | uint16_t allocatedtaglen = 0; |
| 483 | for(int i=0;i<TAG_RESPONSE_COUNT;i++){ |
| 484 | allocatedtaglen += responses[i].response_n; |
| 485 | } |
| 486 | //uint8_t selectOrder = 0; |
| 487 | |
| 488 | BigBuf_free_keep_EM(); |
| 489 | // Allocate 512 bytes for the dynamic modulation, created when the reader queries for it |
| 490 | // Such a response is less time critical, so we can prepare them on the fly |
| 491 | |
| 492 | #define DYNAMIC_RESPONSE_BUFFER_SIZE 256 //max frame size |
| 493 | #define DYNAMIC_MODULATION_BUFFER_SIZE 2 + 9*DYNAMIC_RESPONSE_BUFFER_SIZE //(start and stop bit, 8 bit packet with 1 bit parity |
| 494 | |
| 495 | //uint8_t dynamic_response_buffer[DYNAMIC_RESPONSE_BUFFER_SIZE]; |
| 496 | //uint8_t dynamic_modulation_buffer[DYNAMIC_MODULATION_BUFFER_SIZE]; |
| 497 | uint8_t *dynamic_response_buffer = BigBuf_malloc(DYNAMIC_RESPONSE_BUFFER_SIZE); |
| 498 | uint8_t *dynamic_modulation_buffer = BigBuf_malloc(DYNAMIC_MODULATION_BUFFER_SIZE); |
| 499 | |
| 500 | tag_response_info_t dynamic_response_info = { |
| 501 | .response = dynamic_response_buffer, |
| 502 | .response_n = 0, |
| 503 | .modulation = dynamic_modulation_buffer, |
| 504 | .modulation_n = 0 |
| 505 | }; |
| 506 | // allocate buffers from BigBuf (so we're not in the stack) |
| 507 | uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE); |
| 508 | uint8_t *receivedCmdPar = BigBuf_malloc(MAX_PARITY_SIZE); |
| 509 | //uint8_t* free_buffer_pointer; |
| 510 | //free_buffer_pointer = BigBuf_malloc((allocatedtaglen*8) +(allocatedtaglen) + (TAG_RESPONSE_COUNT * 3)); |
| 511 | BigBuf_malloc((allocatedtaglen*8) +(allocatedtaglen) + (TAG_RESPONSE_COUNT * 3)); |
| 512 | // clear trace |
| 513 | clear_trace(); |
| 514 | set_tracing(TRUE); |
| 515 | |
| 516 | // Prepare the responses of the anticollision phase |
| 517 | // there will be not enough time to do this at the moment the reader sends it REQA |
| 518 | for (size_t i=0; i<TAG_RESPONSE_COUNT; i++) |
| 519 | prepare_allocated_tag_modulation(&responses[i]); |
| 520 | |
| 521 | int len = 0; |
| 522 | |
| 523 | // To control where we are in the protocol |
| 524 | int order = 0; |
| 525 | int lastorder; |
| 526 | int currentblock = 1; //init to 1 |
| 527 | int previousblock = 0; //used to store previous block counter |
| 528 | |
| 529 | // Just to allow some checks |
| 530 | int happened = 0; |
| 531 | int happened2 = 0; |
| 532 | int cmdsRecvd = 0; |
| 533 | |
| 534 | // We need to listen to the high-frequency, peak-detected path. |
| 535 | iso14443a_setup(FPGA_HF_ISO14443A_TAGSIM_LISTEN); |
| 536 | |
| 537 | cmdsRecvd = 0; |
| 538 | tag_response_info_t* p_response; |
| 539 | |
| 540 | LED_A_ON(); |
| 541 | for(;;) { |
| 542 | // Clean receive command buffer |
| 543 | |
| 544 | if(!GetIso14443aCommandFromReader(receivedCmd, receivedCmdPar, &len)) { |
| 545 | DbpString("Button press"); |
| 546 | break; |
| 547 | } |
| 548 | |
| 549 | p_response = NULL; |
| 550 | |
| 551 | // Okay, look at the command now. |
| 552 | previousblock = currentblock; //get previous block |
| 553 | lastorder = order; |
| 554 | currentblock = receivedCmd[0] & 0x01; |
| 555 | |
| 556 | if(receivedCmd[0] == 0x26) { // Received a REQUEST |
| 557 | p_response = &responses[ATR]; order = REQA; |
| 558 | } else if(receivedCmd[0] == 0x52) { // Received a WAKEUP |
| 559 | p_response = &responses[ATR]; order = WUPA; |
| 560 | } else if(receivedCmd[1] == 0x20 && receivedCmd[0] == 0x93) { // Received request for UID (cascade 1) |
| 561 | p_response = &responses[UID1]; order = SELUID1; |
| 562 | } else if(receivedCmd[1] == 0x20 && receivedCmd[0] == 0x95) { // Received request for UID (cascade 2) |
| 563 | p_response = &responses[UID2]; order = SELUID2; |
| 564 | } else if(receivedCmd[1] == 0x70 && receivedCmd[0] == 0x93) { // Received a SELECT (cascade 1) |
| 565 | p_response = &responses[SELACK1]; order = SEL1; |
| 566 | } else if(receivedCmd[1] == 0x70 && receivedCmd[0] == 0x95) { // Received a SELECT (cascade 2) |
| 567 | p_response = &responses[SELACK2]; order = SEL2; |
| 568 | } else if((receivedCmd[0] & 0xA2) == 0xA2){ //R-Block received |
| 569 | if(previousblock == currentblock){ //rule 11, retransmit last block |
| 570 | p_response = &dynamic_response_info; |
| 571 | } else { |
| 572 | if((receivedCmd[0] & 0xB2) == 0xB2){ //RNAK, rule 12 |
| 573 | if(currentblock == 0) |
| 574 | p_response = &responses[RACK0]; |
| 575 | else |
| 576 | p_response = &responses[RACK1]; |
| 577 | } else { |
| 578 | //rule 13 |
| 579 | //TODO: implement chaining |
| 580 | } |
| 581 | } |
| 582 | } |
| 583 | else if(receivedCmd[0] == 0xD0){ //Protocol and parameter selection response |
| 584 | p_response = &responses[PPSresponse]; |
| 585 | order = PPS; |
| 586 | } |
| 587 | else if(receivedCmd[0] == 0x30) { // Received a (plain) READ |
| 588 | //we're an EMV card - so no read commands |
| 589 | p_response = NULL; |
| 590 | } else if(receivedCmd[0] == 0x50) { // Received a HALT |
| 591 | LogTrace(receivedCmd, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, TRUE); |
| 592 | p_response = NULL; |
| 593 | order = HLTA; |
| 594 | } else if(receivedCmd[0] == 0x60 || receivedCmd[0] == 0x61) { // Received an authentication request |
| 595 | p_response = &responses[AUTH_ANS]; |
| 596 | order = AUTH; |
| 597 | } else if(receivedCmd[0] == 0xE0) { // Received a RATS request |
| 598 | readerPacketLen = GetReaderLength(receivedCmd); //get length of supported packet |
| 599 | p_response = &responses[ATS]; |
| 600 | order = RATS; |
| 601 | } else if (order == AUTH && len == 8) { // Received {nr] and {ar} (part of authentication) |
| 602 | LogTrace(receivedCmd, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, TRUE); |
| 603 | uint32_t nr = bytes_to_num(receivedCmd,4); |
| 604 | uint32_t ar = bytes_to_num(receivedCmd+4,4); |
| 605 | Dbprintf("Auth attempt {nr}{ar}: %08x %08x",nr,ar); |
| 606 | } else { |
| 607 | // Check for ISO 14443A-4 compliant commands, look at left nibble |
| 608 | switch (receivedCmd[0]) { |
| 609 | case 0x0B: |
| 610 | case 0x0A: // IBlock (command) |
| 611 | case 0x02: |
| 612 | case 0x03: { |
| 613 | dynamic_response_info.response_n = 0; |
| 614 | dynamic_response_info.response[0] = receivedCmd[0]; // copy PCB |
| 615 | //dynamic_response_info.response[1] = receivedCmd[1]; // copy PCB |
| 616 | dynamic_response_info.response_n++ ; |
| 617 | switch(receivedCmd[1]) { |
| 618 | case 0x00: |
| 619 | switch(receivedCmd[2]){ |
| 620 | case 0xA4: //select |
| 621 | if(receivedCmd[5] == 0x0E){ |
| 622 | } |
| 623 | else if(receivedCmd[5] == 0x07){ |
| 624 | //selectOrder = 0; |
| 625 | } |
| 626 | else{ //send not supported msg |
| 627 | memcpy(dynamic_response_info.response+1, "\x6a\x82", 2); |
| 628 | dynamic_response_info.response_n += 2; |
| 629 | } |
| 630 | break; |
| 631 | case 0xB2: //read record |
| 632 | if(receivedCmd[3] == 0x01 && receivedCmd[4] == 0x0C){ |
| 633 | dynamic_response_info.response_n += 2; |
| 634 | Dbprintf("READ RECORD 1 1"); |
| 635 | } |
| 636 | break; |
| 637 | } |
| 638 | break; |
| 639 | case 0x80: |
| 640 | switch(receivedCmd[2]){ |
| 641 | case 0xA8: //get processing options |
| 642 | break; |
| 643 | } |
| 644 | } |
| 645 | }break; |
| 646 | case 0x1A: |
| 647 | case 0x1B: { // Chaining command |
| 648 | dynamic_response_info.response[0] = 0xaa | ((receivedCmd[0]) & 1); |
| 649 | dynamic_response_info.response_n = 2; |
| 650 | } break; |
| 651 | |
| 652 | case 0xaa: |
| 653 | case 0xbb: { |
| 654 | dynamic_response_info.response[0] = receivedCmd[0] ^ 0x11; |
| 655 | dynamic_response_info.response_n = 2; |
| 656 | } break; |
| 657 | |
| 658 | case 0xBA: { // |
| 659 | memcpy(dynamic_response_info.response,"\xAB\x00",2); |
| 660 | dynamic_response_info.response_n = 2; |
| 661 | } break; |
| 662 | |
| 663 | case 0xCA: |
| 664 | case 0xC2: { // Readers sends deselect command |
| 665 | //we send the command back - this is what tags do in android implemenation i believe - peterfillmore |
| 666 | memcpy(dynamic_response_info.response,receivedCmd,1); |
| 667 | dynamic_response_info.response_n = 1; |
| 668 | } break; |
| 669 | |
| 670 | default: { |
| 671 | // Never seen this command before |
| 672 | LogTrace(receivedCmd, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, TRUE); |
| 673 | Dbprintf("Received unknown command (len=%d):",len); |
| 674 | Dbhexdump(len,receivedCmd,false); |
| 675 | // Do not respond |
| 676 | dynamic_response_info.response_n = 0; |
| 677 | } break; |
| 678 | } |
| 679 | |
| 680 | if (dynamic_response_info.response_n > 0) { |
| 681 | // Copy the CID from the reader query |
| 682 | //dynamic_response_info.response[1] = receivedCmd[1]; |
| 683 | |
| 684 | // Add CRC bytes, always used in ISO 14443A-4 compliant cards |
| 685 | AppendCrc14443a(dynamic_response_info.response,dynamic_response_info.response_n); |
| 686 | dynamic_response_info.response_n += 2; |
| 687 | if(dynamic_response_info.response_n > readerPacketLen){ //throw error if our reader doesn't support the send packet length |
| 688 | Dbprintf("Error: tag response is longer then what the reader supports, TODO:implement command chaining"); |
| 689 | LogTrace(receivedCmd, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, TRUE); |
| 690 | break; |
| 691 | } |
| 692 | if (prepare_tag_modulation(&dynamic_response_info,DYNAMIC_MODULATION_BUFFER_SIZE) == false) { |
| 693 | Dbprintf("Error preparing tag response"); |
| 694 | LogTrace(receivedCmd, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, TRUE); |
| 695 | break; |
| 696 | } |
| 697 | p_response = &dynamic_response_info; |
| 698 | } |
| 699 | } |
| 700 | |
| 701 | // Count number of wakeups received after a halt |
| 702 | if(order == HLTA && lastorder == PPS) { happened++; } |
| 703 | |
| 704 | // Count number of other messages after a halt |
| 705 | if(order != HLTA && lastorder == PPS) { happened2++; } |
| 706 | |
| 707 | if(cmdsRecvd > 999) { |
| 708 | DbpString("1000 commands later..."); |
| 709 | break; |
| 710 | } |
| 711 | cmdsRecvd++; |
| 712 | |
| 713 | if (p_response != NULL) { |
| 714 | EmSendCmd14443aRaw(p_response->modulation, p_response->modulation_n, receivedCmd[0] == 0x52); |
| 715 | // do the tracing for the previous reader request and this tag answer: |
| 716 | uint8_t par[MAX_PARITY_SIZE] = {0x00}; |
| 717 | GetParity(p_response->response, p_response->response_n, par); |
| 718 | |
| 719 | EmLogTrace(Uart.output, |
| 720 | Uart.len, |
| 721 | Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, |
| 722 | Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, |
| 723 | Uart.parity, |
| 724 | p_response->response, |
| 725 | p_response->response_n, |
| 726 | LastTimeProxToAirStart*16 + DELAY_ARM2AIR_AS_TAG, |
| 727 | (LastTimeProxToAirStart + p_response->ProxToAirDuration)*16 + DELAY_ARM2AIR_AS_TAG, |
| 728 | par); |
| 729 | } |
| 730 | |
| 731 | if (!tracing) { |
| 732 | Dbprintf("Trace Full. Simulation stopped."); |
| 733 | break; |
| 734 | } |
| 735 | } |
| 736 | |
| 737 | Dbprintf("%x %x %x", happened, happened2, cmdsRecvd); |
| 738 | LED_A_OFF(); |
| 739 | BigBuf_free_keep_EM(); |
| 740 | } |