NFC: Implement DESFire ISO 7816 command wrapping

This commit is contained in:
Willy-JL
2025-03-20 04:10:19 +00:00
parent 19ee0f4598
commit cc789115dd
5 changed files with 106 additions and 15 deletions

View File

@@ -5,6 +5,14 @@
#define MF_DESFIRE_FFF_PICC_PREFIX "PICC"
#define MF_DESFIRE_FFF_APP_PREFIX "Application"
// ISO 7816 command wrapping
#define MF_DESFIRE_CMD_ISO_CLA (0x90)
#define MF_DESFIRE_CMD_ISO_P1 (0x00)
#define MF_DESFIRE_CMD_ISO_P2 (0x00)
#define MF_DESFIRE_CMD_ISO_LE (0x00)
// ISO 7816 status wrapping
#define MF_DESFIRE_STATUS_ISO_SW1 (0x91)
// Successful operation
#define MF_DESFIRE_STATUS_OPERATION_OK (0x00)
// No changes done to backup files, CommitTransaction / AbortTransaction not necessary

View File

@@ -38,6 +38,26 @@ typedef struct {
MfDesfirePollerEventData* data; /**< Pointer to event specific data. */
} MfDesfirePollerEvent;
/**
* @brief Enumeration of possible MfDesfire poller command modes.
*/
typedef enum {
MfDesfirePollerCommandModeNative, /**< Native MfDesfire commands. */
MfDesfirePollerCommandModeIsoWrapped, /**< ISO 7816-wrapped commands. */
MfDesfirePollerCommandModeMAX,
} MfDesfirePollerCommandMode;
/**
* @brief Change MfDesfire command mode used in poller mode.
*
* @param[in, out] instance pointer to the instance to affect.
* @param[in] command_mode command mode to use in further communication with the card.
*/
void mf_desfire_poller_set_command_mode(
MfDesfirePoller* instance,
MfDesfirePollerCommandMode command_mode);
/**
* @brief Transmit and receive MfDesfire chunks in poller mode.
*

View File

@@ -33,6 +33,16 @@ MfDesfireError mf_desfire_process_status_code(uint8_t status_code) {
}
}
void mf_desfire_poller_set_command_mode(
MfDesfirePoller* instance,
MfDesfirePollerCommandMode command_mode) {
furi_check(instance);
furi_check(instance->state == MfDesfirePollerStateIdle);
furi_check(command_mode < MfDesfirePollerCommandModeMAX);
instance->command_mode = command_mode;
}
MfDesfireError mf_desfire_poller_send_chunks(
MfDesfirePoller* instance,
const BitBuffer* tx_buffer,
@@ -45,10 +55,27 @@ MfDesfireError mf_desfire_poller_send_chunks(
furi_check(rx_buffer);
MfDesfireError error = MfDesfireErrorNone;
uint8_t status_code = MF_DESFIRE_STATUS_OPERATION_OK;
do {
bit_buffer_reset(instance->tx_buffer);
if(instance->command_mode == MfDesfirePollerCommandModeNative) {
bit_buffer_append(instance->tx_buffer, tx_buffer);
} else if(instance->command_mode == MfDesfirePollerCommandModeIsoWrapped) {
bit_buffer_append_byte(instance->tx_buffer, MF_DESFIRE_CMD_ISO_CLA);
bit_buffer_append_byte(instance->tx_buffer, bit_buffer_get_byte(tx_buffer, 0));
bit_buffer_append_byte(instance->tx_buffer, MF_DESFIRE_CMD_ISO_P1);
bit_buffer_append_byte(instance->tx_buffer, MF_DESFIRE_CMD_ISO_P2);
if(bit_buffer_get_size_bytes(tx_buffer) > 1) {
bit_buffer_append_byte(
instance->tx_buffer, bit_buffer_get_size_bytes(tx_buffer) - 1);
bit_buffer_append_right(instance->tx_buffer, tx_buffer, 1);
}
bit_buffer_append_byte(instance->tx_buffer, MF_DESFIRE_CMD_ISO_LE);
}
Iso14443_4aError iso14443_4a_error = iso14443_4a_poller_send_block(
instance->iso14443_4a_poller, tx_buffer, instance->rx_buffer);
instance->iso14443_4a_poller, instance->tx_buffer, instance->rx_buffer);
if(iso14443_4a_error != Iso14443_4aErrorNone) {
error = mf_desfire_process_error(iso14443_4a_error);
@@ -56,16 +83,38 @@ MfDesfireError mf_desfire_poller_send_chunks(
}
bit_buffer_reset(instance->tx_buffer);
bit_buffer_append_byte(instance->tx_buffer, MF_DESFIRE_STATUS_ADDITIONAL_FRAME);
if(bit_buffer_get_size_bytes(instance->rx_buffer) > sizeof(uint8_t)) {
bit_buffer_copy_right(rx_buffer, instance->rx_buffer, sizeof(uint8_t));
} else {
bit_buffer_reset(rx_buffer);
if(instance->command_mode == MfDesfirePollerCommandModeNative) {
bit_buffer_append_byte(instance->tx_buffer, MF_DESFIRE_STATUS_ADDITIONAL_FRAME);
} else if(instance->command_mode == MfDesfirePollerCommandModeIsoWrapped) {
bit_buffer_append_byte(instance->tx_buffer, MF_DESFIRE_CMD_ISO_CLA);
bit_buffer_append_byte(instance->tx_buffer, MF_DESFIRE_STATUS_ADDITIONAL_FRAME);
bit_buffer_append_byte(instance->tx_buffer, MF_DESFIRE_CMD_ISO_P1);
bit_buffer_append_byte(instance->tx_buffer, MF_DESFIRE_CMD_ISO_P2);
bit_buffer_append_byte(instance->tx_buffer, MF_DESFIRE_CMD_ISO_LE);
}
while(
bit_buffer_starts_with_byte(instance->rx_buffer, MF_DESFIRE_STATUS_ADDITIONAL_FRAME)) {
size_t response_len = bit_buffer_get_size_bytes(instance->rx_buffer);
status_code = MF_DESFIRE_STATUS_LENGTH_ERROR;
bit_buffer_reset(rx_buffer);
if(instance->command_mode == MfDesfirePollerCommandModeNative &&
response_len >= sizeof(uint8_t)) {
status_code = bit_buffer_get_byte(instance->rx_buffer, 0);
if(response_len > sizeof(uint8_t)) {
bit_buffer_copy_right(rx_buffer, instance->rx_buffer, sizeof(uint8_t));
}
} else if(
instance->command_mode == MfDesfirePollerCommandModeIsoWrapped &&
response_len >= 2 * sizeof(uint8_t) &&
bit_buffer_get_byte(instance->rx_buffer, response_len - 2) ==
MF_DESFIRE_STATUS_ISO_SW1) {
status_code = bit_buffer_get_byte(instance->rx_buffer, response_len - 1);
if(response_len > 2 * sizeof(uint8_t)) {
bit_buffer_copy_left(
rx_buffer, instance->rx_buffer, response_len - 2 * sizeof(uint8_t));
}
}
while(status_code == MF_DESFIRE_STATUS_ADDITIONAL_FRAME) {
Iso14443_4aError iso14443_4a_error = iso14443_4a_poller_send_block(
instance->iso14443_4a_poller, instance->tx_buffer, instance->rx_buffer);
@@ -78,17 +127,29 @@ MfDesfireError mf_desfire_poller_send_chunks(
const size_t rx_capacity_remaining =
bit_buffer_get_capacity_bytes(rx_buffer) - bit_buffer_get_size_bytes(rx_buffer);
if(rx_size <= rx_capacity_remaining + 1) {
bit_buffer_append_right(rx_buffer, instance->rx_buffer, sizeof(uint8_t));
} else {
FURI_LOG_W(TAG, "RX buffer overflow: ignoring %zu bytes", rx_size - 1);
if(instance->command_mode == MfDesfirePollerCommandModeNative) {
status_code = rx_size < 1 ? MF_DESFIRE_STATUS_LENGTH_ERROR :
bit_buffer_get_byte(instance->rx_buffer, 0);
if(rx_size <= rx_capacity_remaining + 1) {
bit_buffer_append_right(rx_buffer, instance->rx_buffer, sizeof(uint8_t));
} else {
FURI_LOG_W(TAG, "RX buffer overflow: ignoring %zu bytes", rx_size - 1);
}
} else if(instance->command_mode == MfDesfirePollerCommandModeIsoWrapped) {
status_code = rx_size < 2 ? MF_DESFIRE_STATUS_LENGTH_ERROR :
bit_buffer_get_byte(instance->rx_buffer, rx_size - 1);
if(rx_size <= rx_capacity_remaining + 2) {
bit_buffer_set_size_bytes(instance->rx_buffer, rx_size - 2);
bit_buffer_append(rx_buffer, instance->rx_buffer);
} else {
FURI_LOG_W(TAG, "RX buffer overflow: ignoring %zu bytes", rx_size - 2);
}
}
}
} while(false);
if(error == MfDesfireErrorNone) {
uint8_t err_code = bit_buffer_get_byte(instance->rx_buffer, 0);
error = mf_desfire_process_status_code(err_code);
error = mf_desfire_process_status_code(status_code);
}
return error;

View File

@@ -30,6 +30,7 @@ typedef enum {
struct MfDesfirePoller {
Iso14443_4aPoller* iso14443_4a_poller;
MfDesfirePollerCommandMode command_mode;
MfDesfirePollerSessionState session_state;
MfDesfirePollerState state;
MfDesfireError error;

View File

@@ -2654,6 +2654,7 @@ Function,+,mf_desfire_poller_read_key_versions,MfDesfireError,"MfDesfirePoller*,
Function,+,mf_desfire_poller_read_version,MfDesfireError,"MfDesfirePoller*, MfDesfireVersion*"
Function,+,mf_desfire_poller_select_application,MfDesfireError,"MfDesfirePoller*, const MfDesfireApplicationId*"
Function,+,mf_desfire_poller_send_chunks,MfDesfireError,"MfDesfirePoller*, const BitBuffer*, BitBuffer*"
Function,+,mf_desfire_poller_set_command_mode,void,"MfDesfirePoller*, MfDesfirePollerCommandMode"
Function,+,mf_desfire_reset,void,MfDesfireData*
Function,+,mf_desfire_save,_Bool,"const MfDesfireData*, FlipperFormat*"
Function,+,mf_desfire_set_uid,_Bool,"MfDesfireData*, const uint8_t*, size_t"
1 entry status name type params
2654 Function + mf_desfire_poller_read_version MfDesfireError MfDesfirePoller*, MfDesfireVersion*
2655 Function + mf_desfire_poller_select_application MfDesfireError MfDesfirePoller*, const MfDesfireApplicationId*
2656 Function + mf_desfire_poller_send_chunks MfDesfireError MfDesfirePoller*, const BitBuffer*, BitBuffer*
2657 Function + mf_desfire_poller_set_command_mode void MfDesfirePoller*, MfDesfirePollerCommandMode
2658 Function + mf_desfire_reset void MfDesfireData*
2659 Function + mf_desfire_save _Bool const MfDesfireData*, FlipperFormat*
2660 Function + mf_desfire_set_uid _Bool MfDesfireData*, const uint8_t*, size_t