From f5dc8ab42f4cd6076ee04a049a4a8cdad581df3c Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Fri, 28 Aug 2026 13:43:11 +0800 Subject: [PATCH] FIxing bugs from 76181dfb8 and 377d7cd61 FIxing bugs from 76181dfb8 and 377d7cd61 breaking secure channel operations --- armsrc/sam_picopass.c | 5 +++++ armsrc/sam_sc.c | 32 ++++++++++++++++++++++++-------- armsrc/sam_seos.c | 5 +++++ 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/armsrc/sam_picopass.c b/armsrc/sam_picopass.c index d79dfe4b4..0f7172283 100644 --- a/armsrc/sam_picopass.c +++ b/armsrc/sam_picopass.c @@ -17,6 +17,7 @@ //----------------------------------------------------------------------------- #include "sam_picopass.h" #include "sam_common.h" +#include "sam_sc.h" #include "iclass.h" #include "crc16.h" #include "proxmark3_arm.h" @@ -636,6 +637,10 @@ int sam_picopass_get_pacs(PacketCommandNG *c) { uint8_t sam_response_len = 0; clear_trace(); + // This path resets the SAM, invalidating any secure-channel state held by + // CMD_HF_SAM_SC. Ensure the next SC request reopens instead of sending + // into a reset SAM with a stale routing/session flag. + sam_sc_session_invalidate(); I2C_Reset_EnterMainProgram(); set_tracing(true); diff --git a/armsrc/sam_sc.c b/armsrc/sam_sc.c index dc8c32b73..bf2b3eba5 100644 --- a/armsrc/sam_sc.c +++ b/armsrc/sam_sc.c @@ -492,30 +492,46 @@ void sam_sc_handler(const PacketCommandNG *c) { LED_D_ON(); set_tracing(true); + int res = PM3_SUCCESS; + // Reset the SAM only if the caller asked for it OR this is the first SC // op since boot / since the previous session was released. Crucially // this dispatcher does NOT reset on every call the way sam_picopass_get_pacs // does, so the SAM-side session-flag binding established by ContinueAuth // survives across multiple CMD_HF_SAM_SC invocations. // - // After every reset we issue a sam_get_version() warmup ping. This - // mirrors what sam_picopass_get_pacs does (which is what `hf iclass sam - // --info` runs through). Without this warmup, the FIRST sam_send_payload_ex - // after I2C_Reset can time out - the 8051<->SAM UART link needs a - // sacrificial round-trip to settle. The version response is discarded. + // A module reset can leave an ATR pending and returns the module UART to + // its default rate. Consume the ATR first: besides preventing it from + // colliding with the warmup APDU, GetATR() restores the cached PPS rate so + // the module and SAM are synchronized again. This mirrors the direct + // PICOPASS SAM path. + // + // Then issue a sam_get_version() warmup ping. Without it, the first real + // sam_send_payload_ex() after I2C_Reset can time out while the 8051<->SAM + // UART link settles. Do not enter a session when either stage fails. // // NOTE: HF_SELECT / HF_OFF must NOT trigger a reset - they run inside an // already-open SC session and a reset would wipe the SAM-side session-flag // binding. They pass neither force_reset nor a cleared session flag. if (force_reset || s_sam_sc_session_active == false) { + // A forced reset may replace an otherwise valid active session. Do not + // leave it marked live if ATR recovery or the warmup subsequently + // fails. + s_sam_sc_session_active = false; I2C_Reset_EnterMainProgram(); StartTicks(); - sam_get_version(false); + smart_card_atr_t card; + if (GetATR(&card, false) == false) { + res = PM3_ECARDEXCHANGE; + goto out; + } + res = sam_get_version(false); + if (res != PM3_SUCCESS) { + goto out; + } s_sam_sc_session_active = true; } - int res = PM3_SUCCESS; - // ---- HF_OFF: disarm the field (no SAM traffic) ---- if (hf_off) { switch_off(); diff --git a/armsrc/sam_seos.c b/armsrc/sam_seos.c index f0ff823fc..f99a7f2a1 100644 --- a/armsrc/sam_seos.c +++ b/armsrc/sam_seos.c @@ -18,6 +18,7 @@ //----------------------------------------------------------------------------- #include "sam_seos.h" #include "sam_common.h" +#include "sam_sc.h" #include "iclass.h" #include "proxmark3_arm.h" @@ -291,6 +292,10 @@ int sam_seos_get_pacs(PacketCommandNG *c) { int res = PM3_EFAILED; clear_trace(); + // Like the PICOPASS dispatcher, this reset destroys a live SC session. + // Mark it stale so the next CMD_HF_SAM_SC call performs its reset/ATR + // synchronization path before sending a secured APDU. + sam_sc_session_invalidate(); I2C_Reset_EnterMainProgram(); set_tracing(true);