`hf emrtd` implementation deadlocks UART with NG frames
Describe the bug This is a continuation of #1714 with better reproducibility steps and a patch that fixes the problem, but probably introduces other problems.
The bug seems to be more general and to do with the way the packets are being sent via UART on macOS.
To Reproduce
- Compile latest pm3 + firmware on macOS.
- Flash the firmware onto the Proxmark 3.
- Grab a passport utilizing
ISO/IEC 14443(B)as a communication standard. - Run
hf emrtd info.
Expected behavior Details of passport being printed.
Instead, observed behavior is:
[usb] pm3 --> hf emrtd info -m xyz
[=] ..
[=] Authentication is enforced
[=] Switching to external authentication...
[=] External authentication with BAC successful.
[=] ------------------ Basic Info ------------------
[+] Communication standard: ISO/IEC 14443(B)
[+] Authentication........: Enforced
[+] PACE..................: Available
[+] Authentication result.: Successful
[=] ----------------- EF_CardAccess ----------------
[+] PACE version..........: 2
[+] PACE algorithm........: ECDH, Generic Mapping, AES-CMAC-256
[+] PACE parameter........: NIST P-256 (secp256r1)
[=] You can cancel this operation by pressing the pm3 button
[!!] 🚨 APDU: reply timeout
[!!] 🚨 Failed to secure select 011E
[!!] 🚨 Failed to read EF_COM.
After minimum viable patch from below is applied, passport is read successfully:
[=] ..
[=] Authentication is enforced
[=] Switching to external authentication...
[=] External authentication with BAC successful.
[=] ------------------ Basic Info ------------------
[+] Communication standard: ISO/IEC 14443(B)
[+] Authentication........: Enforced
[+] PACE..................: Available
[+] Authentication result.: Successful
[=] ----------------- EF_CardAccess ----------------
[+] PACE version..........: 2
[+] PACE algorithm........: ECDH, Generic Mapping, AES-CMAC-256
[+] PACE parameter........: NIST P-256 (secp256r1)
[=] ..
[=] -------------------- EF_COM --------------------
[+] EF_DG1 ...............: Details recorded in MRZ
[+] EF_DG2 ...............: Encoded Face
[+] EF_DG14...............: Security Options
[=] ...............
[=] ..
[=] -------------------- EF_DG1 --------------------
[+] Document Type.........: Passport
[+] Document Form Factor..: TD3
[+] Issuing state.........: GBR
[+] Nationality...........: GBR
[... omitted ...]
Desktop (please complete the following information):
- OS: macOS Somoa
[usb] pm3 --> hw version
[ Proxmark3 RFID instrument ]
[ Client ]
Iceman/master/v4.18218-49-g99571f328-dirty-suspect 2024-03-02 20:44:16 490a2c900
compiled with............. Clang/LLVM Apple LLVM 15.0.0 (clang-1500.0.40.1)
platform.................. OSX / x86_64
Readline support.......... present
QT GUI support............ absent
native BT support......... absent
Python script support..... absent
Lua SWIG support.......... present
Python SWIG support....... absent
[ Proxmark3 ]
firmware.................. PM3 GENERIC
[ ARM ]
bootrom: Iceman/master/v4.18218-49-g99571f328-dirty-suspect 2024-03-02 20:43:53 490a2c900
os: Iceman/master/v4.18218-49-g99571f328-dirty-suspect 2024-03-02 20:44:01 490a2c900
compiled with GCC 10.3.1 20210824 (release)
[ FPGA ]
fpga_pm3_lf.ncd image 2s30vq100 2024-02-03 15:12:10
fpga_pm3_hf.ncd image 2s30vq100 2024-02-03 15:12:20
fpga_pm3_felica.ncd image 2s30vq100 2024-02-03 15:12:41
fpga_pm3_hf_15.ncd image 2s30vq100 2024-02-03 15:12:31
[ Hardware ]
--= uC: AT91SAM7S512 Rev A
--= Embedded Processor: ARM7TDMI
--= Internal SRAM size: 64K bytes
--= Architecture identifier: AT91SAM7Sxx Series
--= Embedded flash memory 512K bytes ( 62% used )
[#] Memory
[#] BigBuf_size............. 41648
[#] Available memory........ 37804
[#] Tracing
[#] tracing ................ 1
[#] traceLen ............... 4694
[#] Current FPGA image
[#] mode.................... fpga_pm3_hf.ncd image 2s30vq100 2024-02-03 15:12:20
[#] LF Sampling config
[#] [q] divisor............. 95 ( 125.00 kHz )
[#] [b] bits per sample..... 8
[#] [d] decimation.......... 1
[#] [a] averaging........... yes
[#] [t] trigger threshold... 0
[#] [s] samples to skip..... 0
[#]
[#] LF T55XX config
[#] [r] [a] [b] [c] [d] [e] [f] [g]
[#] mode |start|write|write|write| read|write|write
[#] | gap | gap | 0 | 1 | gap | 2 | 3
[#] ---------------------------+-----+-----+-----+-----+-----+-----+------
[#] fixed bit length (default) | 31 | 20 | 18 | 50 | 15 | n/a | n/a |
[#] long leading reference | 31 | 20 | 18 | 50 | 15 | n/a | n/a |
[#] leading zero | 31 | 20 | 18 | 40 | 15 | n/a | n/a |
[#] 1 of 4 coding reference | 31 | 20 | 18 | 34 | 15 | 50 | 66 |
[#]
[#] HF 14a config
[#] [a] Anticol override.... std ( follow standard )
[#] [b] BCC override........ std ( follow standard )
[#] [2] CL2 override........ std ( follow standard )
[#] [3] CL3 override........ std ( follow standard )
[#] [r] RATS override....... std ( follow standard )
[#] Transfer Speed
[#] Sending packets to client...
[#] Time elapsed................... 500ms
[#] Bytes transferred.............. 346624
[#] Transfer Speed PM3 -> Client... 693248 bytes/s
[#] Various
[#] Max stack usage......... 3952 / 8480 bytes
[#] Debug log level......... 1 ( error )
[#] ToSendMax............... 30
[#] ToSend BUFFERSIZE....... 2308
[#] Slow clock.............. 30537 Hz
[#] Installed StandAlone Mode
[#] LF HID26 standalone - aka SamyRun (Samy Kamkar)
[#]
Additional context
Upon research on #2289 with three separate passports issued by different countries, I managed to trace down the issue and "fix" it.
In particular:
- Hungarian passport issued in 2019 using
ISO/IEC 14443(A)w/ optional PACE support worked fine. - UK passport issued 2024 using
ISO/IEC 14443(B)w/ optional PACE support results in the crash seem above. - Polish passport issued 2014 using
ISO/IEC 14443(A)w/o PACE support works fine.
Then after debugging the exact communications path differences, I noticed the following:
- Passport using NFC-A send data via
ExchangeAPDU14a(), and they communicate fine. - Passports using NFC-B send data via
exchange_14b_apdu(), and they cause the device to crash.
Enabling
#define COMMS_DEBUG
#define COMMS_DEBUG_RAW
in client/src/comms.c indicated that:
- NFC-A passports use the
MIXframes in the appropriate function to talk to the pm3 - NFC-B passports use the
NGframes to talk to the pm3
After extensive debugging across the comms path on both the client-side and the device-side, it seems that:
- the client successfully sends the data to the Proxmark via UART
- however, the device firmware never processes the data, in particular, sending debug messages from
receive_ng_internaldo not get sent from the device and it ends up being locked
Therefore, as receive_ng() is continuously called from the event loop in the firmware, it seems that receive_ng never passes control over to receive_ng_internal.
This led to the minium viable fix for the issue, which is:
diff --git a/armsrc/cmd.c b/armsrc/cmd.c
index ee2565cd2..fb0ea539d 100644
--- a/armsrc/cmd.c
+++ b/armsrc/cmd.c
@@ -232,7 +232,7 @@ static int receive_ng_internal(PacketCommandNG *rx, uint32_t read_ng(uint8_t *da
int receive_ng(PacketCommandNG *rx) {
// Check if there is a packet available
- if (usb_poll_validate_length())
+ if (usb_check())
return receive_ng_internal(rx, usb_read_ng, true, false);
#ifdef WITH_FPC_USART_HOST
Unfortunately, as usb_poll_validate_length was introduced for a reason, this is likely not the correct fix, but it does cause the passport to be read correctly on macOS.
I hope this framing of the issue will make it easier to track down the cause, which now looks likely to be related to the uart implementations in the macOS POSIX SDK instead of the emrtd code path specifically.
Great write-up with the communications.
I believe the issue is inside uint32_t usb_read_ng(uint8_t *data, size_t len)