Merge pull request #3300 from Antiklesys/master

Added SC Operations
This commit is contained in:
Iceman
2026-05-11 10:49:50 +02:00
committed by GitHub
12 changed files with 1228 additions and 30 deletions
+1
View File
@@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file.
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...
## [unreleased][unreleased]
- Added secure channel operations to `hf iclass sam` and fixed/improved I2C bus operations (@antiklesys)
- Added `hf calypso list` command (@kormax)
- Added `hf mfd verifycert` command (@kormax)
- Added `hf calypso dump` command (@kormax)
+1 -1
View File
@@ -36,7 +36,7 @@ APP_CFLAGS = $(PLATFORM_DEFS)
SRC_LF = lfops.c lfsampling.c pcf7931.c lfdemod.c lfadc.c
SRC_HF = hfops.c
SRC_ISO15693 = iso15693.c iso15693tools.c
SRC_ISO14443a = iso14443a.c secc.c mifareutil.c mifarecmd.c epa.c mifaresim.c sam_common.c sam_mfc.c sam_seos.c
SRC_ISO14443a = iso14443a.c secc.c mifareutil.c mifarecmd.c epa.c mifaresim.c sam_common.c sam_mfc.c sam_seos.c sam_sc.c
#UNUSED: mifaresniff.c
SRC_ISO14443b = iso14443b.c
+6
View File
@@ -69,6 +69,7 @@
#include "sam_picopass.h"
#include "sam_seos.h"
#include "sam_mfc.h"
#include "sam_sc.h"
#include "cmac_calc.h"
#ifdef WITH_LCD
@@ -2530,6 +2531,11 @@ static void PacketReceived(PacketCommandNG *packet) {
break;
}
case CMD_HF_SAM_SC: {
sam_sc_handler(packet);
break;
}
#endif
#ifdef WITH_FPC_USART
+43 -16
View File
@@ -187,9 +187,8 @@ static bool WaitSCL_L(void) {
return WaitSCL_L_delay(5000);
}
// Wait max 1800ms or until SCL goes LOW.
// It timeout reading response from card
// Which ever comes first
// Wait up to 1200ms or until SCL goes LOW, whichever comes first.
// Used to bound the timeout while reading a response from the card.
static bool WaitSCL_L_timeout(void) {
volatile uint32_t delay = 1200;
while (delay--) {
@@ -199,7 +198,7 @@ static bool WaitSCL_L_timeout(void) {
WaitMS(1);
}
return (delay == 0);
return false;
}
static bool I2C_Start(void) {
@@ -489,8 +488,9 @@ bool I2C_BufferWrite(const uint8_t *data, uint16_t len, uint8_t device_cmd, uint
// len = uint16 because we need to read up to 256bytes
int16_t I2C_BufferRead(uint8_t *data, uint16_t len, uint8_t device_cmd, uint8_t device_address) {
// sanity check
if (data == NULL || len == 0) {
// sanity check - need at least 2 bytes for the SIM-module length header
// (the response format prepends a 2-byte BE length); fewer cannot be parsed.
if (data == NULL || len < 2) {
return 0;
}
@@ -858,7 +858,11 @@ void SmartCardRaw(const smart_card_raw_t *p) {
uint16_t len = 0;
uint8_t *resp = BigBuf_calloc(ISO7816_MAX_FRAME);
// check if alloacted...
if (resp == NULL) {
reply_ng(CMD_SMART_RAW, PM3_EMALLOC, NULL, 0);
LEDsoff();
return;
}
smartcard_command_t flags = p->flags;
if ((flags & SC_CLEARLOG) == SC_CLEARLOG)
@@ -888,7 +892,10 @@ void SmartCardRaw(const smart_card_raw_t *p) {
uint32_t wait = SIM_WAIT_DELAY;
if ((flags & SC_WAIT) == SC_WAIT) {
wait = (uint32_t)((p->wait_delay * 1000) / 3.07);
// wait_delay is in ms; one WaitSCL_H_delay iteration is ~3.07us.
// Integer-only conversion via uint64_t to avoid soft-float and avoid
// overflow at large wait_delay values: (ms * 100000 + 153) / 307.
wait = (uint32_t)(((uint64_t)p->wait_delay * 100000U + 153U) / 307U);
}
LogTrace(p->data, p->len, 0, 0, NULL, true);
@@ -900,8 +907,10 @@ void SmartCardRaw(const smart_card_raw_t *p) {
I2C_DEVICE_ADDRESS_MAIN
);
if (res == false && g_dbglevel > 3) {
DbpString(I2C_ERROR);
if (res == false) {
if (g_dbglevel > 3) {
DbpString(I2C_ERROR);
}
reply_ng(CMD_SMART_RAW, PM3_ESOFT, NULL, 0);
goto OUT;
}
@@ -937,7 +946,12 @@ void SmartCardUpgrade(uint64_t arg0) {
bool isOK = true;
uint16_t length = arg0, pos = 0;
const uint8_t *fwdata = BigBuf_get_addr();
uint8_t *verfiydata = BigBuf_calloc(I2C_BLOCK_SIZE);
uint8_t *verifydata = BigBuf_calloc(I2C_BLOCK_SIZE);
if (verifydata == NULL) {
reply_ng(CMD_SMART_UPGRADE, PM3_EMALLOC, NULL, 0);
LED_C_OFF();
return;
}
while (length) {
@@ -951,7 +965,7 @@ void SmartCardUpgrade(uint64_t arg0) {
// write
int16_t res = I2C_WriteFW(fwdata + pos, size, msb, lsb, I2C_DEVICE_ADDRESS_BOOT);
if (!res) {
DbpString("Writing failed");
Dbprintf("Writing failed at offset 0x%04X", pos);
isOK = false;
break;
}
@@ -960,16 +974,16 @@ void SmartCardUpgrade(uint64_t arg0) {
WaitMS(50);
// read
res = I2C_ReadFW(verfiydata, size, msb, lsb, I2C_DEVICE_ADDRESS_BOOT);
res = I2C_ReadFW(verifydata, size, msb, lsb, I2C_DEVICE_ADDRESS_BOOT);
if (res <= 0) {
DbpString("Reading back failed");
Dbprintf("Reading back failed at offset 0x%04X", pos);
isOK = false;
break;
}
// cmp
if (0 != memcmp(fwdata + pos, verfiydata, size)) {
DbpString("not equal data");
if (0 != memcmp(fwdata + pos, verifydata, size)) {
Dbprintf("Verify mismatch at offset 0x%04X", pos);
isOK = false;
break;
}
@@ -983,7 +997,20 @@ void SmartCardUpgrade(uint64_t arg0) {
BigBuf_free();
}
// Send a single byte to the SIM module's CMD_SETBAUD opcode (0x04).
// The 8051 firmware uses this to reload Timer1 (UART0 baud generator).
// Until 2026 the implementation was an empty stub; the SIM module silently
// ignored any host-driven baud renegotiation. Some smart cards (notably the
// HID Artemis SLE88 SAM family) advertise non-default Fi/Di in TA1 and need
// PPS to switch the bridge baud post-ATR.
void SmartCardSetBaud(uint64_t arg0) {
LED_D_ON();
I2C_Reset_EnterMainProgram();
bool ok = I2C_WriteByte((uint8_t)(arg0 & 0xFF),
I2C_DEVICE_CMD_SETBAUD,
I2C_DEVICE_ADDRESS_MAIN);
reply_ng(CMD_SMART_SETBAUD, ok ? PM3_SUCCESS : PM3_ESOFT, NULL, 0);
LEDsoff();
}
void SmartCardSetClock(uint64_t arg0) {
+5 -3
View File
@@ -34,9 +34,11 @@
#define ISO7816_MAX_FRAME 270
// 8051 speaks with smart card.
// 1000*50*3.07 = 153.5ms
// 1 byte transfer == 1ms with max frame being 256 bytes
#define SIM_WAIT_DELAY 150000 // about 270ms delay // 109773 -- about 337.7ms delay
// 1 byte transfer == 1ms with max frame being 256 bytes.
// SIM_WAIT_DELAY is the iteration count passed to WaitSCL_H_delay(); each iter
// is ~3.07us, so 150000 * 3.07us = ~460ms - the upper bound we wait for the
// SIM module to assert SCL after a SIM-side operation.
#define SIM_WAIT_DELAY 150000 // ~460ms total wait via WaitSCL_H_delay
void I2C_recovery(void);
+34 -7
View File
@@ -36,13 +36,25 @@
#include "i2c.h"
#include "i2c_direct.h"
static void SmartCardDirectSend(uint8_t prepend, const smart_card_raw_t *p, uint8_t *output, uint16_t *olen) {
// Maximum chained ISO 7816-4 GET RESPONSE (61xx) follow-ups before bailing.
// A misbehaving card that always returns 61xx would otherwise recurse without
// bound, allocating fresh smart_card_raw_t payloads from BigBuf each time
// until the device wedges. Eight rounds is more than any legitimate APDU
// chain would need.
#define SC_DIRECT_MAX_DEPTH 8
static void SmartCardDirectSend(uint8_t prepend, const smart_card_raw_t *p, uint8_t *output, uint16_t *olen, uint8_t depth) {
LED_D_ON();
uint16_t len = 0;
uint8_t *resp = BigBuf_calloc(ISO7816_MAX_FRAME);
if (resp == NULL) {
Dbprintf("SmartCardDirectSend: BigBuf_calloc failed");
if (olen) *olen = 0;
LEDsoff();
return;
}
resp[0] = prepend;
// check if alloacted...
smartcard_command_t flags = p->flags;
if ((flags & SC_LOG) == SC_LOG)
@@ -70,7 +82,10 @@ static void SmartCardDirectSend(uint8_t prepend, const smart_card_raw_t *p, uint
if (((flags & SC_RAW) == SC_RAW) || ((flags & SC_RAW_T0) == SC_RAW_T0)) {
if ((flags & SC_WAIT) == SC_WAIT) {
wait = (uint32_t)((p->wait_delay * 1000) / 3.07);
// wait_delay is in ms; one WaitSCL_H_delay iteration is ~3.07us.
// Integer-only conversion via uint64_t to avoid soft-float and
// avoid overflow at large wait_delay values.
wait = (uint32_t)(((uint64_t)p->wait_delay * 100000U + 153U) / 307U);
}
LogTrace(p->data, p->len, 0, 0, NULL, true);
@@ -82,8 +97,10 @@ static void SmartCardDirectSend(uint8_t prepend, const smart_card_raw_t *p, uint
I2C_DEVICE_ADDRESS_MAIN
);
if (res == false && g_dbglevel > 3) {
Dbprintf("SmartCardDirectSend: I2C_BufferWrite failed\n");
if (res == false) {
if (g_dbglevel > 3) {
Dbprintf("SmartCardDirectSend: I2C_BufferWrite failed");
}
goto OUT;
}
@@ -98,15 +115,25 @@ static void SmartCardDirectSend(uint8_t prepend, const smart_card_raw_t *p, uint
}
if (len == 2 && resp[1] == 0x61) {
if (depth >= SC_DIRECT_MAX_DEPTH) {
Dbprintf("SmartCardDirectSend: GET RESPONSE chain depth (%u) exceeded; aborting", depth);
goto OUT;
}
uint8_t cmd_getresp[] = {0x00, ISO7816_GET_RESPONSE, 0x00, 0x00, resp[2]};
smart_card_raw_t *payload = (smart_card_raw_t *)BigBuf_calloc(sizeof(smart_card_raw_t) + sizeof(cmd_getresp));
if (payload == NULL) {
Dbprintf("SmartCardDirectSend: GET RESPONSE alloc failed");
goto OUT;
}
payload->flags = SC_RAW | SC_LOG;
payload->len = sizeof(cmd_getresp);
payload->wait_delay = 0;
memcpy(payload->data, cmd_getresp, sizeof(cmd_getresp));
SmartCardDirectSend(prepend, payload, output, olen);
SmartCardDirectSend(prepend, payload, output, olen, depth + 1);
} else if (len == 2) {
Dbprintf("***** BAD response from card (response unsupported)...");
Dbhexdump(3, &resp[0], false);
@@ -199,7 +226,7 @@ int CmdSmartRaw(const uint8_t prepend, const uint8_t *data, int dlen, uint8_t *o
payload->flags |= SC_RAW;
}
SmartCardDirectSend(prepend, payload, output, olen);
SmartCardDirectSend(prepend, payload, output, olen, 0);
return PM3_SUCCESS;
}
+19 -1
View File
@@ -158,6 +158,23 @@ int sam_send_payload(
const uint8_t *const payload,
const uint16_t *payload_len,
uint8_t *response,
uint16_t *response_len
) {
return sam_send_payload_ex(addr_src, addr_dest, addr_reply, 0x00,
payload, payload_len,
response, response_len);
}
int sam_send_payload_ex(
const uint8_t addr_src,
const uint8_t addr_dest,
const uint8_t addr_reply,
const uint8_t scFlag,
const uint8_t *const payload,
const uint16_t *payload_len,
uint8_t *response,
uint16_t *response_len
) {
@@ -171,13 +188,14 @@ int sam_send_payload(
buf[3] = 0x63; // P2
buf[4] = SAM_TX_ASN1_PREFIX_LENGTH + (uint8_t) * payload_len; // LEN
// Grace routing header: FROM, TO, REPLY-TO, 0x00, 0x00, scFlag
buf[5] = addr_src;
buf[6] = addr_dest;
buf[7] = addr_reply;
buf[8] = 0x00;
buf[9] = 0x00;
buf[10] = 0x00;
buf[10] = scFlag;
memcpy(
&buf[11],
+23
View File
@@ -27,6 +27,7 @@ int sam_rxtx(const uint8_t *data, uint16_t n, uint8_t *resp, uint16_t *resplen);
void switch_clock_to_ticks(void);
void switch_clock_to_countsspclk(void);
// Backwards-compatible wrapper that calls sam_send_payload_ex with scFlag=0x00.
int sam_send_payload(
const uint8_t addr_src,
const uint8_t addr_dest,
@@ -39,6 +40,28 @@ int sam_send_payload(
uint16_t *response_len
);
// Extended variant that lets the caller set the Grace routing scFlag byte.
//
// The Grace routing header is 6 bytes: FROM, TO, REPLY-TO, 0x00, 0x00, scFlag.
// During InitAuth the scFlag is 0x00; after the SAM authenticates the host it
// returns a session-bound scFlag (typically 0x81) that must be echoed in the
// routing header of every subsequent wrapped APDU (ContinueAuth, wrap/unwrap).
// The original sam_send_payload hardcoded scFlag=0x00 which made it impossible
// to drive a real secure-channel session. New SC code paths must use this _ex
// variant instead.
int sam_send_payload_ex(
const uint8_t addr_src,
const uint8_t addr_dest,
const uint8_t addr_reply,
const uint8_t scFlag,
const uint8_t *const payload,
const uint16_t *payload_len,
uint8_t *response,
uint16_t *response_len
);
int sam_get_version(bool info);
int sam_get_serial_number(void);
+160
View File
@@ -0,0 +1,160 @@
//-----------------------------------------------------------------------------
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// See LICENSE.txt for the text of the license.
//-----------------------------------------------------------------------------
// HID Artemis SAM secure-channel transport (see sam_sc.h for design notes).
//-----------------------------------------------------------------------------
#include "sam_sc.h"
#include <string.h>
#include "BigBuf.h"
#include "appmain.h"
#include "cmd.h"
#include "dbprint.h"
#include "i2c.h" // ISO7816_MAX_FRAME, I2C_Reset_EnterMainProgram
#include "proxmark3_arm.h"
#include "sam_common.h"
#include "ticks.h"
#include "util.h" // LED_D_ON, LEDsoff
// Tracks whether the SIM module has been initialised since the last reset.
// Set true after the first successful sam_sc_handler() invocation; cleared by
// sam_sc_session_invalidate() (called from any other firmware path that takes
// over the SIM module - currently a manual hook left for future wiring) and
// by SAM_SC_FLAG_FORCE_RESET / SAM_SC_FLAG_RELEASE.
static bool s_sam_sc_session_active = false;
void sam_sc_session_invalidate(void) {
s_sam_sc_session_active = false;
}
void sam_sc_handler(const PacketCommandNG *c) {
if (c == NULL || c->length < SAM_SC_HEADER_LEN) {
reply_ng(CMD_HF_SAM_SC, PM3_EINVARG, NULL, 0);
return;
}
const uint8_t *body = c->data.asBytes;
const uint8_t flags = body[SAM_SC_OFF_FLAGS];
const uint8_t addr_src = body[SAM_SC_OFF_ADDR_SRC];
const uint8_t addr_dest = body[SAM_SC_OFF_ADDR_DEST];
const uint8_t addr_reply = body[SAM_SC_OFF_ADDR_REPLY];
const uint8_t scFlag = body[SAM_SC_OFF_SCFLAG];
const bool force_reset = !!(flags & SAM_SC_FLAG_FORCE_RESET);
const bool release = !!(flags & SAM_SC_FLAG_RELEASE);
const bool no_payload = !!(flags & SAM_SC_FLAG_NO_PAYLOAD);
const uint8_t *payload = body + SAM_SC_HEADER_LEN;
uint16_t payload_len = (uint16_t)(c->length - SAM_SC_HEADER_LEN);
if (no_payload) {
// Caller is just managing session state (open/close); no SAM traffic.
payload_len = 0;
} else if (payload_len == 0) {
reply_ng(CMD_HF_SAM_SC, PM3_EINVARG, NULL, 0);
return;
}
LED_D_ON();
set_tracing(true);
// 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.
if (force_reset || s_sam_sc_session_active == false) {
I2C_Reset_EnterMainProgram();
StartTicks();
sam_get_version(false);
s_sam_sc_session_active = true;
}
int res = PM3_SUCCESS;
if (no_payload == false) {
uint8_t *response = BigBuf_calloc(ISO7816_MAX_FRAME);
if (response == NULL) {
res = PM3_EMALLOC;
goto out;
}
uint16_t response_len = ISO7816_MAX_FRAME;
res = sam_send_payload_ex(
addr_src, addr_dest, addr_reply, scFlag,
payload, &payload_len,
response, &response_len
);
if (res != PM3_SUCCESS) {
// Whatever happened on the wire, the session may be in an
// inconsistent state. Mark dirty so the next call re-opens.
s_sam_sc_session_active = false;
}
if (release) {
// Caller requested an explicit teardown after this op (typically
// after a samCommandSecureChannelTerminate). Do a full reset to
// bring the SAM back to a clean idle state.
I2C_Reset_EnterMainProgram();
s_sam_sc_session_active = false;
}
// Reformat the buffer for the host: prepend the SAM-assigned scFlag
// (firmware-side index 4 of the routing tail), then the SAM payload
// (firmware-side index 5 onward). See sam_sc.h for the wire layout.
// memmove is safe across the overlapping ranges (dst < src by 4).
if (res == PM3_SUCCESS && response_len >= 6) {
uint8_t sc_flag = response[4];
uint16_t sam_payload_len = (uint16_t)(response_len - 5);
memmove(response + 1, response + 5, sam_payload_len);
response[0] = sc_flag;
response_len = (uint16_t)(1 + sam_payload_len);
reply_ng(CMD_HF_SAM_SC, PM3_SUCCESS, response, response_len);
} else if (res == PM3_SUCCESS) {
// sam_send_payload_ex succeeded but the response is too short
// to contain a routing tail + SAM payload. Treat as exchange
// error so the host knows the result is unusable.
reply_ng(CMD_HF_SAM_SC, PM3_ECARDEXCHANGE, NULL, 0);
} else {
// sam_send_payload_ex failed. Propagate the error; no payload.
reply_ng(CMD_HF_SAM_SC, res, NULL, 0);
}
BigBuf_free();
goto done;
}
// SAM_SC_FLAG_NO_PAYLOAD path: caller wants to manage session state only.
if (release) {
I2C_Reset_EnterMainProgram();
s_sam_sc_session_active = false;
}
out:
reply_ng(CMD_HF_SAM_SC, res, NULL, 0);
done:
set_tracing(false);
LEDsoff();
}
+96
View File
@@ -0,0 +1,96 @@
//-----------------------------------------------------------------------------
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// See LICENSE.txt for the text of the license.
//-----------------------------------------------------------------------------
// HID Artemis SAM secure-channel transport.
//
// CMD_HF_SAM_PICOPASS is structurally unsuitable for sustaining an SCP02 /
// Grace secure channel because it (a) hard-resets the SAM at the start of
// every CLI invocation, wiping the SAM's internal session-flag binding, and
// (b) routes raw payloads through sam_send_request_iso15 whose loop is
// designed to relay 0x61-tagged SAM responses to an iCLASS card via NFC.
//
// This handler is a separate dispatcher that:
// - Resets the SAM only on the very first call after device boot, OR when
// the host explicitly asks for a reset.
// - Skips the sam_get_version sanity ping.
// - Sends a single SAM payload with a host-supplied scFlag and returns the
// SAM's raw response - no NFC card-edge involvement at all.
//
// The host owns the SCP02 / Grace KDF + wrap/unwrap state machine; this
// firmware module is a thin transport pipe so that state can survive across
// CLI invocations on the SAM side.
//-----------------------------------------------------------------------------
#ifndef __SAM_SC_H
#define __SAM_SC_H
#include "common.h"
#include "pm3_cmd.h"
// CMD_HF_SAM_SC payload layout:
//
// [0] flags byte
// BITMASK(0) SAM_SC_FLAG_FORCE_RESET - I2C_Reset before this op,
// marks session uninitialised
// BITMASK(1) SAM_SC_FLAG_RELEASE - I2C_Reset after this op,
// marks session uninitialised
// BITMASK(2) SAM_SC_FLAG_NO_PAYLOAD - send no payload, just
// manage session state
// (open / close)
// [1] addr_src Grace routing FROM byte (typically 0x44)
// [2] addr_dest Grace routing TO byte (typically 0x0A = SAM)
// [3] addr_reply Grace routing REPLY-TO (typically 0x44)
// [4] scFlag Grace routing scFlag (0x00 for InitAuth;
// server-assigned thereafter)
// [5...] SAM payload bytes starting with 0xA0 (or whatever SAM TLV the
// host wants delivered raw; the firmware does not interpret).
//
// Reply: reply_ng(CMD_HF_SAM_SC, status, payload, payload_len)
// payload[0] = SAM-assigned scFlag (the byte the host MUST echo in the
// routing header of the next request - 0x00 during
// InitAuth, server-assigned thereafter)
// payload[1..] = raw SAM response starting at the first byte after the
// routing tail (typically 0xBD for Path A/B, 0xBE for
// Path C errorResponse)
// payload_len = 1 + len(SAM response)
//
// The scFlag is the load-bearing piece of state for sustaining a Grace
// secure channel: the SAM assigns it during InitAuth and binds the
// authenticated session to it. Subsequent ContinueAuth and wrapped APDUs
// MUST carry the same scFlag in their outgoing routing header or the SAM
// will reject them. Surfacing it as the first byte of the reply lets the
// host save and replay it on the next CMD_HF_SAM_SC call without any
// additional probing.
#define SAM_SC_FLAG_FORCE_RESET (1 << 0)
#define SAM_SC_FLAG_RELEASE (1 << 1)
#define SAM_SC_FLAG_NO_PAYLOAD (1 << 2)
// Wire-layout offsets within the CMD_HF_SAM_SC packet body.
#define SAM_SC_OFF_FLAGS 0
#define SAM_SC_OFF_ADDR_SRC 1
#define SAM_SC_OFF_ADDR_DEST 2
#define SAM_SC_OFF_ADDR_REPLY 3
#define SAM_SC_OFF_SCFLAG 4
#define SAM_SC_HEADER_LEN 5
void sam_sc_handler(const PacketCommandNG *c);
// Forces the next sam_sc_handler() call to perform an I2C reset before sending
// its payload. Intended to be called by other firmware paths that may have
// taken over the SIM module (e.g. CMD_HF_SAM_PICOPASS, CMD_SMART_*) and would
// otherwise leave a stale "session active" flag visible to sam_sc_handler.
void sam_sc_session_invalidate(void);
#endif
File diff suppressed because it is too large Load Diff
+6
View File
@@ -892,6 +892,12 @@ typedef struct {
#define CMD_HF_SEOS_SIMULATE 0x0903
// HID SAM secure-channel transport (separate dispatcher from CMD_HF_SAM_PICOPASS).
// Used to drive InitAuth / ContinueAuth / wrap-unwrap traffic where the SAM's
// session state must persist across calls (no I2C reset, no GetVersion ping,
// no iso15 NFC-relay loop) and the routing scFlag byte must be host-supplied.
#define CMD_HF_SAM_SC 0x0904
#define CMD_UNKNOWN 0xFFFF
// Mifare simulation flags