Skip to content

Commit e10e113

Browse files
authored
Merge pull request #3022 from team-orangeBlue/14b-ndef-fix
Fix ISO14443-4 type B NDEF processing
2 parents f20d8f3 + 2a5cb01 commit e10e113

File tree

2 files changed

+134
-34
lines changed

2 files changed

+134
-34
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file.
33
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
44

55
## [unreleased][unreleased]
6+
- Fixed ISO14443-4 type B NDEF workflow + parsing (@team-orangeBlue)
67
- Added Snapmaker U1 filament spool KDF in `hf mf keygen` (@Foxushka)
78
- Replaced `hf mf bambukeys` with `hf mf keygen` with multiple KDFs support (@Foxushka)
89
- Fix `hf seos adf/pacs` handling of cards with different diversifier lengths and different ADF OIDs (@nvx)

client/src/cmdhf14b.c

Lines changed: 133 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -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

26582757
static int CmdHF14BView(const char *Cmd) {

0 commit comments

Comments
 (0)