proxmark3 icon indicating copy to clipboard operation
proxmark3 copied to clipboard

`hf emrtd` implementation deadlocks UART with NG frames

Open marcellp opened this issue 2 years ago • 2 comments

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

  1. Compile latest pm3 + firmware on macOS.
  2. Flash the firmware onto the Proxmark 3.
  3. Grab a passport utilizing ISO/IEC 14443(B) as a communication standard.
  4. 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 MIX frames in the appropriate function to talk to the pm3
  • NFC-B passports use the NG frames 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_internal do 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.

marcellp avatar Mar 02 '24 21:03 marcellp

Great write-up with the communications.

iceman1001 avatar Mar 03 '24 09:03 iceman1001

I believe the issue is inside uint32_t usb_read_ng(uint8_t *data, size_t len)

iceman1001 avatar Mar 03 '24 11:03 iceman1001