@@ -2568,91 +2568,190 @@ int CmdHF14BNdefRead(const char *Cmd) {
25682568 // --------------- Select NDEF Tag application ----------------
25692569 uint8_t aSELECT_AID[80];
25702570 int aSELECT_AID_n = 0;
2571- param_gethex_to_eol("00a4040007d276000085010100", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n);
2571+ // It's likely safe to ignore the backwards compatibility select that's present in the 14443A part of this code.
2572+ // Full-fledged 14443B is rare, after all. And if not.. your eMRTD passport doesn't have NDEF for a fact.
2573+ param_gethex_to_eol("00a4040007d276000085010100", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n); // Select NDEF application D2760000850101
25722574 int res = exchange_14b_apdu(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen, -1);
25732575 if (res) {
2574- goto out;
2576+ switch_off_field_14b();
2577+ return res;
25752578 }
25762579
25772580 if (resplen < 2) {
25782581 res = PM3_ESOFT;
2579- goto out;
2582+ switch_off_field_14b();
2583+ return res;
25802584 }
25812585
25822586 uint16_t sw = get_sw(response, resplen);
25832587 if (sw != ISO7816_OK) {
2584- PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
2588+ PrintAndLogEx(ERR, "Selecting NDEF AID failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
25852589 res = PM3_ESOFT;
2586- goto out;
2590+ switch_off_field_14b();
2591+ return res;
25872592 }
25882593
25892594 activate_field = false;
25902595 keep_field_on = true;
2591- // --------------- Send CC select ----------------
2592- // --------------- Read binary ----------------
25932596
2594- // --------------- NDEF file reading ----------------
2595- uint8_t aSELECT_FILE_NDEF[30];
2596- int aSELECT_FILE_NDEF_n = 0;
2597- param_gethex_to_eol("00a4000c020001", 0, aSELECT_FILE_NDEF, sizeof(aSELECT_FILE_NDEF), &aSELECT_FILE_NDEF_n);
2598- res = exchange_14b_apdu(aSELECT_FILE_NDEF, aSELECT_FILE_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen, -1);
2599- if (res)
2600- goto out;
2597+ // --------------- CC file reading ----------------
2598+ uint8_t aSELECT_FILE_CC[30];
2599+ int aSELECT_FILE_CC_n = 0;
2600+ param_gethex_to_eol("00a4000c02e103", 0, aSELECT_FILE_CC, sizeof(aSELECT_FILE_CC), &aSELECT_FILE_CC_n); // Select E103 file with payload information
2601+ res = exchange_14b_apdu(aSELECT_FILE_CC, aSELECT_FILE_CC_n, activate_field, keep_field_on, response, sizeof(response), &resplen, -1);
2602+ if (res) {
2603+ switch_off_field_14b();
2604+ return res;
2605+ }
26012606
26022607 sw = get_sw(response, resplen);
26032608 if (sw != ISO7816_OK) {
2604- PrintAndLogEx(ERR, "Selecting NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
2609+ PrintAndLogEx(ERR, "Selecting CC file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
26052610 res = PM3_ESOFT;
2606- goto out;
2611+ switch_off_field_14b();
2612+ return res;
26072613 }
26082614
26092615 // --------------- Read binary ----------------
2610- uint8_t aREAD_NDEF [30];
2611- int aREAD_NDEF_n = 0;
2612- param_gethex_to_eol("00b0000002 ", 0, aREAD_NDEF , sizeof(aREAD_NDEF ), &aREAD_NDEF_n );
2613- res = exchange_14b_apdu(aREAD_NDEF, aREAD_NDEF_n , activate_field, keep_field_on, response, sizeof(response), &resplen, -1);
2616+ uint8_t aREAD_CC [30];
2617+ int aREAD_CC_n = 0;
2618+ param_gethex_to_eol("00b000000f ", 0, aREAD_CC , sizeof(aREAD_CC ), &aREAD_CC_n );
2619+ res = exchange_14b_apdu(aREAD_CC, aREAD_CC_n , activate_field, keep_field_on, response, sizeof(response), &resplen, -1);
26142620 if (res) {
2615- goto out;
2621+ switch_off_field_14b();
2622+ return res;
26162623 }
26172624
26182625 sw = get_sw(response, resplen);
26192626 if (sw != ISO7816_OK) {
2620- PrintAndLogEx(ERR, "reading NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
2627+ PrintAndLogEx(ERR, "reading CC file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
26212628 res = PM3_ESOFT;
2622- goto out;
2629+ switch_off_field_14b();
2630+ return res;
26232631 }
26242632 // take offset from response
26252633 uint8_t offset = response[1];
2626-
2627- // --------------- Read binary w offset ----------------
2628- keep_field_on = false;
2634+
2635+ // Parse CC data
2636+ uint8_t cc_data[resplen - 2];
2637+ memcpy(cc_data, response, sizeof(cc_data));
2638+ uint8_t file_id[2] = {cc_data[9], cc_data[10]};
2639+
2640+
2641+ uint16_t max_rapdu_size = (cc_data[3] << 8 | cc_data[4]) - 2;
2642+
2643+ max_rapdu_size = max_rapdu_size < sizeof(response) - 2 ? max_rapdu_size : sizeof(response) - 2;
2644+ // --------------- NDEF file reading ----------------
2645+ uint8_t aSELECT_FILE_NDEF[30];
2646+ int aSELECT_FILE_NDEF_n = 0;
2647+ param_gethex_to_eol("00a4000c02", 0, aSELECT_FILE_NDEF, sizeof(aSELECT_FILE_NDEF), &aSELECT_FILE_NDEF_n);
2648+ memcpy(aSELECT_FILE_NDEF + aSELECT_FILE_NDEF_n, file_id, sizeof(file_id));
2649+ res = exchange_14b_apdu(aSELECT_FILE_NDEF, aSELECT_FILE_NDEF_n + sizeof(file_id), activate_field, keep_field_on, response, sizeof(response), &resplen, -1);
2650+ if (res != PM3_SUCCESS) {
2651+ switch_off_field_14b();
2652+ return res;
2653+ }
2654+ sw = get_sw(response, resplen);
2655+ if (sw != ISO7816_OK) {
2656+ PrintAndLogEx(ERR, "Selecting NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
2657+ switch_off_field_14b();
2658+ return PM3_ESOFT;
2659+ }
2660+ // --------------- Read binary size ----------------
2661+ uint8_t aREAD_NDEF[30];
2662+ int aREAD_NDEF_n = 0;
26292663 aREAD_NDEF_n = 0;
2630- param_gethex_to_eol("00b00002", 0, aREAD_NDEF, sizeof(aREAD_NDEF), &aREAD_NDEF_n);
2631- aREAD_NDEF[4] = offset;
2664+ param_gethex_to_eol("00b0000002", 0, aREAD_NDEF, sizeof(aREAD_NDEF), &aREAD_NDEF_n);
26322665 res = exchange_14b_apdu(aREAD_NDEF, aREAD_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen, -1);
26332666 if (res) {
2634- goto out;
2667+ switch_off_field_14b();
2668+ return res;
26352669 }
26362670
26372671 sw = get_sw(response, resplen);
26382672 if (sw != ISO7816_OK) {
26392673 PrintAndLogEx(ERR, "reading NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
26402674 res = PM3_ESOFT;
2641- goto out;
2675+ switch_off_field_14b();
2676+ return res;
2677+ }
2678+
2679+ uint16_t ndef_size = (response[0] << 8) + response[1];
2680+ offset = 2;
2681+
2682+ uint8_t *ndef_file = calloc(ndef_size, sizeof(uint8_t));
2683+ if (ndef_file == NULL) {
2684+ PrintAndLogEx(WARNING, "Failed to allocate memory");
2685+ switch_off_field_14b();
2686+ return PM3_EMALLOC;
2687+ }
2688+
2689+ if (ndef_size + offset > 0xFFFF) {
2690+ PrintAndLogEx(ERR, "NDEF size abnormally large in CmdHF14BNdefRead(). Aborting...\n");
2691+ free(ndef_file);
2692+ switch_off_field_14b();
2693+ return PM3_EOVFLOW;
2694+ }
2695+ for (size_t i = offset; i < ndef_size + offset; i += max_rapdu_size) {
2696+ size_t segment_size = max_rapdu_size < ndef_size + offset - i ? max_rapdu_size : ndef_size + offset - i;
2697+
2698+ keep_field_on = i < ndef_size + offset - max_rapdu_size;
2699+ aREAD_NDEF_n = 0;
2700+ param_gethex_to_eol("00b00000", 0, aREAD_NDEF, sizeof(aREAD_NDEF), &aREAD_NDEF_n);
2701+ aREAD_NDEF[2] = i >> 8;
2702+ aREAD_NDEF[3] = i & 0xFF;
2703+
2704+ // Segment_size is stuffed into a single-byte field below ... so error out if overflows
2705+ if (segment_size > 0xFFu) {
2706+ PrintAndLogEx(ERR, "Segment size too large (0x%zx > 0xFF)", segment_size);
2707+ switch_off_field_14b();
2708+ free(ndef_file);
2709+ return PM3_EOVFLOW;
2710+ }
2711+ aREAD_NDEF[4] = segment_size;
2712+
2713+ res = exchange_14b_apdu(aREAD_NDEF, aREAD_NDEF_n + 1, activate_field, keep_field_on, response, sizeof(response), &resplen, -1);
2714+ if (res != PM3_SUCCESS) {
2715+ switch_off_field_14b();
2716+ free(ndef_file);
2717+ return res;
2718+ }
2719+
2720+ sw = get_sw(response, resplen);
2721+ if (sw != ISO7816_OK) {
2722+ PrintAndLogEx(ERR, "reading NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
2723+ switch_off_field_14b();
2724+ free(ndef_file);
2725+ return PM3_ESOFT;
2726+ }
2727+
2728+ if (resplen != segment_size + 2) {
2729+ PrintAndLogEx(ERR, "reading NDEF file failed, expected %zu bytes, got %i bytes.", segment_size, resplen - 2);
2730+ switch_off_field_14b();
2731+ free(ndef_file);
2732+ return PM3_ESOFT;
2733+ }
2734+
2735+ memcpy(ndef_file + (i - offset), response, segment_size);
26422736 }
26432737
2738+ if (verbose == false) {
2739+ PrintAndLogEx(HINT, "Hint: Try " _YELLOW_("`hf 14b ndefread -v`") " for more details"); // So far this prints absolutely nothing
2740+ }
2741+
2742+
26442743 // get total NDEF length before save. If fails, we save it all
26452744 size_t n = 0;
26462745 if (NDEFGetTotalLength(response + 2, resplen - 4, &n) != PM3_SUCCESS)
26472746 n = resplen - 4;
26482747
26492748 pm3_save_dump(filename, response + 2, n, jsfNDEF);
26502749
2651- res = NDEFRecordsDecodeAndPrint(response + 2, resplen - 4 , verbose);
2652-
2653- out:
2750+ NDEFRecordsDecodeAndPrint(ndef_file, ndef_size , verbose);
2751+ free(ndef_file);
2752+ PrintAndLogEx(NORMAL, "");
26542753 switch_off_field_14b();
2655- return res ;
2754+ return PM3_SUCCESS ;
26562755}
26572756
26582757static int CmdHF14BView(const char *Cmd) {
0 commit comments