Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

hf emrtd implementation deadlocks UART with NG frames #2311

Open
marcellp opened this issue Mar 2, 2024 · 2 comments
Open

hf emrtd implementation deadlocks UART with NG frames #2311

marcellp opened this issue Mar 2, 2024 · 2 comments

Comments

@marcellp
Copy link

marcellp commented Mar 2, 2024

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.

@iceman1001
Copy link
Collaborator

Great write-up with the communications.

@iceman1001
Copy link
Collaborator

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants