mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-04-24 03:29:57 -07:00
NFC: Support creating NDEF AID on DESFire
This commit is contained in:
@@ -17,6 +17,8 @@ extern "C" {
|
||||
#define MF_DESFIRE_CMD_GET_FILE_IDS (0x6F)
|
||||
#define MF_DESFIRE_CMD_GET_FILE_SETTINGS (0xF5)
|
||||
|
||||
#define MF_DESFIRE_CMD_CREATE_APPLICATION (0xCA)
|
||||
|
||||
#define MF_DESFIRE_CMD_READ_DATA (0xBD)
|
||||
#define MF_DESFIRE_CMD_GET_VALUE (0x6C)
|
||||
#define MF_DESFIRE_CMD_READ_RECORDS (0xBB)
|
||||
|
||||
@@ -75,17 +75,17 @@ bool mf_desfire_free_memory_parse(MfDesfireFreeMemory* data, const BitBuffer* bu
|
||||
return can_parse;
|
||||
}
|
||||
|
||||
bool mf_desfire_key_settings_parse(MfDesfireKeySettings* data, const BitBuffer* buf) {
|
||||
typedef struct FURI_PACKED {
|
||||
bool is_master_key_changeable : 1;
|
||||
bool is_free_directory_list : 1;
|
||||
bool is_free_create_delete : 1;
|
||||
bool is_config_changeable : 1;
|
||||
uint8_t change_key_id : 4;
|
||||
uint8_t max_keys : 4;
|
||||
uint8_t flags : 4;
|
||||
} MfDesfireKeySettingsLayout;
|
||||
typedef struct FURI_PACKED {
|
||||
bool is_master_key_changeable : 1;
|
||||
bool is_free_directory_list : 1;
|
||||
bool is_free_create_delete : 1;
|
||||
bool is_config_changeable : 1;
|
||||
uint8_t change_key_id : 4;
|
||||
uint8_t max_keys : 4;
|
||||
uint8_t flags : 4;
|
||||
} MfDesfireKeySettingsLayout;
|
||||
|
||||
bool mf_desfire_key_settings_parse(MfDesfireKeySettings* data, const BitBuffer* buf) {
|
||||
const bool can_parse = bit_buffer_get_size_bytes(buf) == sizeof(MfDesfireKeySettingsLayout);
|
||||
|
||||
if(can_parse) {
|
||||
@@ -105,6 +105,21 @@ bool mf_desfire_key_settings_parse(MfDesfireKeySettings* data, const BitBuffer*
|
||||
return can_parse;
|
||||
}
|
||||
|
||||
void mf_desfire_key_settings_dump(const MfDesfireKeySettings* data, BitBuffer* buf) {
|
||||
MfDesfireKeySettingsLayout layout;
|
||||
|
||||
layout.is_master_key_changeable = data->is_master_key_changeable;
|
||||
layout.is_free_directory_list = data->is_free_directory_list;
|
||||
layout.is_free_create_delete = data->is_free_create_delete;
|
||||
layout.is_config_changeable = data->is_config_changeable;
|
||||
|
||||
layout.change_key_id = data->change_key_id;
|
||||
layout.max_keys = data->max_keys;
|
||||
layout.flags = data->flags;
|
||||
|
||||
bit_buffer_append_bytes(buf, (uint8_t*)&layout, sizeof(MfDesfireKeySettingsLayout));
|
||||
}
|
||||
|
||||
bool mf_desfire_key_version_parse(MfDesfireKeyVersion* data, const BitBuffer* buf) {
|
||||
const bool can_parse = bit_buffer_get_size_bytes(buf) == sizeof(MfDesfireKeyVersion);
|
||||
|
||||
|
||||
@@ -68,6 +68,8 @@ bool mf_desfire_free_memory_parse(MfDesfireFreeMemory* data, const BitBuffer* bu
|
||||
|
||||
bool mf_desfire_key_settings_parse(MfDesfireKeySettings* data, const BitBuffer* buf);
|
||||
|
||||
void mf_desfire_key_settings_dump(const MfDesfireKeySettings* data, BitBuffer* buf);
|
||||
|
||||
bool mf_desfire_key_version_parse(MfDesfireKeyVersion* data, const BitBuffer* buf);
|
||||
|
||||
bool mf_desfire_application_id_parse(
|
||||
|
||||
@@ -187,6 +187,27 @@ MfDesfireError mf_desfire_poller_read_file_settings_multi(
|
||||
const SimpleArray* file_ids,
|
||||
SimpleArray* data);
|
||||
|
||||
/**
|
||||
* @brief Create Application on MfDesfire card.
|
||||
*
|
||||
* Must ONLY be used inside the callback function.
|
||||
*
|
||||
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||
* @param[in] id pointer to the application id for the new application.
|
||||
* @param[in] key_settings pointer to the key settings for the new application.
|
||||
* @param[in] iso_df_id optional identifier for the new application.
|
||||
* @param[in] iso_df_name optional name for the new application.
|
||||
* @param[in] iso_df_name_len length of the optional application name.
|
||||
* @return MfDesfireErrorNone on success, an error code on failure.
|
||||
*/
|
||||
MfDesfireError mf_desfire_poller_create_application(
|
||||
MfDesfirePoller* instance,
|
||||
const MfDesfireApplicationId* id,
|
||||
const MfDesfireKeySettings* key_settings,
|
||||
uint16_t iso_df_id,
|
||||
const uint8_t* iso_df_name,
|
||||
uint8_t iso_df_name_len);
|
||||
|
||||
/**
|
||||
* @brief Read file data on MfDesfire card.
|
||||
*
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "mf_desfire_poller_i.h"
|
||||
|
||||
#include <furi.h>
|
||||
#include <bit_lib/bit_lib.h>
|
||||
|
||||
#include "mf_desfire_i.h"
|
||||
|
||||
@@ -329,6 +330,40 @@ MfDesfireError mf_desfire_poller_read_file_settings_multi(
|
||||
return error;
|
||||
}
|
||||
|
||||
MfDesfireError mf_desfire_poller_create_application(
|
||||
MfDesfirePoller* instance,
|
||||
const MfDesfireApplicationId* id,
|
||||
const MfDesfireKeySettings* key_settings,
|
||||
uint16_t iso_df_id,
|
||||
const uint8_t* iso_df_name,
|
||||
uint8_t iso_df_name_len) {
|
||||
furi_check(instance);
|
||||
|
||||
bit_buffer_reset(instance->input_buffer);
|
||||
bit_buffer_append_byte(instance->input_buffer, MF_DESFIRE_CMD_CREATE_APPLICATION);
|
||||
bit_buffer_append_bytes(
|
||||
instance->input_buffer, (const uint8_t*)id, sizeof(MfDesfireApplicationId));
|
||||
mf_desfire_key_settings_dump(key_settings, instance->input_buffer);
|
||||
|
||||
if(iso_df_name && iso_df_name_len) {
|
||||
uint8_t ks2_pos = bit_buffer_get_size_bytes(instance->input_buffer) - 1;
|
||||
uint8_t ks2 = bit_buffer_get_byte(instance->input_buffer, ks2_pos);
|
||||
ks2 |= (1 << 5); // Mark file id present
|
||||
bit_buffer_set_byte(instance->input_buffer, ks2_pos, ks2);
|
||||
|
||||
uint8_t iso_file_id_le[sizeof(iso_df_id)];
|
||||
bit_lib_num_to_bytes_le(iso_df_id, sizeof(iso_file_id_le), iso_file_id_le);
|
||||
bit_buffer_append_bytes(instance->input_buffer, iso_file_id_le, sizeof(iso_file_id_le));
|
||||
|
||||
bit_buffer_append_bytes(instance->input_buffer, iso_df_name, iso_df_name_len);
|
||||
}
|
||||
|
||||
MfDesfireError error =
|
||||
mf_desfire_send_chunks(instance, instance->input_buffer, instance->result_buffer);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static MfDesfireError mf_desfire_poller_read_file(
|
||||
MfDesfirePoller* instance,
|
||||
MfDesfireFileId id,
|
||||
|
||||
@@ -68,7 +68,6 @@ static NfcCommand type_4_tag_poller_handler_request_mode(Type4TagPoller* instanc
|
||||
|
||||
static NfcCommand type_4_tag_poller_handler_detect_platform(Type4TagPoller* instance) {
|
||||
instance->error = type_4_tag_poller_detect_platform(instance);
|
||||
iso14443_4a_poller_halt(instance->iso14443_4a_poller);
|
||||
if(instance->error == Type4TagErrorNone) {
|
||||
FURI_LOG_D(TAG, "Detect platform success");
|
||||
} else {
|
||||
@@ -76,6 +75,8 @@ static NfcCommand type_4_tag_poller_handler_detect_platform(Type4TagPoller* inst
|
||||
}
|
||||
instance->state = Type4TagPollerStateSelectApplication;
|
||||
|
||||
// Reset card state so platform-specific commands do not interfere
|
||||
iso14443_4a_poller_halt(instance->iso14443_4a_poller);
|
||||
return NfcCommandReset;
|
||||
}
|
||||
|
||||
@@ -89,6 +90,9 @@ static NfcCommand type_4_tag_poller_handler_select_app(Type4TagPoller* instance)
|
||||
if(instance->mode == Type4TagPollerModeWrite &&
|
||||
instance->error == Type4TagErrorCardUnformatted) {
|
||||
instance->state = Type4TagPollerStateCreateApplication;
|
||||
// Reset card state so platform-specific commands do not interfere
|
||||
iso14443_4a_poller_halt(instance->iso14443_4a_poller);
|
||||
return NfcCommandReset;
|
||||
} else {
|
||||
instance->state = Type4TagPollerStateFailed;
|
||||
}
|
||||
@@ -109,6 +113,9 @@ static NfcCommand type_4_tag_poller_handler_read_cc(Type4TagPoller* instance) {
|
||||
if(instance->mode == Type4TagPollerModeWrite &&
|
||||
instance->error == Type4TagErrorCardUnformatted) {
|
||||
instance->state = Type4TagPollerStateCreateCapabilityContainer;
|
||||
// Reset card state so platform-specific commands do not interfere
|
||||
iso14443_4a_poller_halt(instance->iso14443_4a_poller);
|
||||
return NfcCommandReset;
|
||||
} else {
|
||||
instance->state = Type4TagPollerStateFailed;
|
||||
}
|
||||
@@ -134,7 +141,10 @@ static NfcCommand type_4_tag_poller_handler_create_app(Type4TagPoller* instance)
|
||||
instance->error = type_4_tag_poller_create_app(instance);
|
||||
if(instance->error == Type4TagErrorNone) {
|
||||
FURI_LOG_D(TAG, "Create application success");
|
||||
// Reset card state so platform-specific commands do not interfere
|
||||
instance->state = Type4TagPollerStateSelectApplication;
|
||||
iso14443_4a_poller_halt(instance->iso14443_4a_poller);
|
||||
return NfcCommandReset;
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Failed to create application");
|
||||
instance->state = Type4TagPollerStateFailed;
|
||||
@@ -147,7 +157,10 @@ static NfcCommand type_4_tag_poller_handler_create_cc(Type4TagPoller* instance)
|
||||
instance->error = type_4_tag_poller_create_cc(instance);
|
||||
if(instance->error == Type4TagErrorNone) {
|
||||
FURI_LOG_D(TAG, "Create CC success");
|
||||
instance->state = Type4TagPollerStateReadCapabilityContainer;
|
||||
// Reset card state so platform-specific commands do not interfere
|
||||
instance->state = Type4TagPollerStateSelectApplication;
|
||||
iso14443_4a_poller_halt(instance->iso14443_4a_poller);
|
||||
return NfcCommandReset;
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Failed to create CC");
|
||||
instance->state = Type4TagPollerStateFailed;
|
||||
@@ -160,7 +173,10 @@ static NfcCommand type_4_tag_poller_handler_create_ndef(Type4TagPoller* instance
|
||||
instance->error = type_4_tag_poller_create_ndef(instance);
|
||||
if(instance->error == Type4TagErrorNone) {
|
||||
FURI_LOG_D(TAG, "Create NDEF success");
|
||||
instance->state = Type4TagPollerStateWriteNdefMessage;
|
||||
// Reset card state so platform-specific commands do not interfere
|
||||
instance->state = Type4TagPollerStateSelectApplication;
|
||||
iso14443_4a_poller_halt(instance->iso14443_4a_poller);
|
||||
return NfcCommandReset;
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Failed to create NDEF");
|
||||
instance->state = Type4TagPollerStateFailed;
|
||||
@@ -179,6 +195,9 @@ static NfcCommand type_4_tag_poller_handler_write_ndef(Type4TagPoller* instance)
|
||||
if(instance->mode == Type4TagPollerModeWrite &&
|
||||
instance->error == Type4TagErrorCardUnformatted) {
|
||||
instance->state = Type4TagPollerStateCreateNdefMessage;
|
||||
// Reset card state so platform-specific commands do not interfere
|
||||
iso14443_4a_poller_halt(instance->iso14443_4a_poller);
|
||||
return NfcCommandReset;
|
||||
} else {
|
||||
instance->state = Type4TagPollerStateFailed;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <bit_lib/bit_lib.h>
|
||||
|
||||
#include <nfc/nfc_device.h>
|
||||
#include <nfc/protocols/mf_desfire/mf_desfire_poller.h>
|
||||
#include <nfc/protocols/mf_desfire/mf_desfire_poller_defs.h>
|
||||
|
||||
#define TAG "Type4TagPoller"
|
||||
@@ -199,7 +200,7 @@ Type4TagError type_4_tag_poller_detect_platform(Type4TagPoller* instance) {
|
||||
|
||||
do {
|
||||
FURI_LOG_D(TAG, "Detect DESFire");
|
||||
NfcGenericInstance* mf_des = mf_desfire_poller.alloc(instance->iso14443_4a_poller);
|
||||
MfDesfirePoller* mf_des = mf_desfire_poller.alloc(instance->iso14443_4a_poller);
|
||||
if(mf_desfire_poller.detect(event, mf_des)) {
|
||||
platform = Type4TagPlatformMfDesfire;
|
||||
nfc_device_set_data(device, NfcProtocolMfDesfire, mf_desfire_poller.get_data(mf_des));
|
||||
@@ -303,8 +304,56 @@ Type4TagError type_4_tag_poller_read_ndef(Type4TagPoller* instance) {
|
||||
}
|
||||
|
||||
Type4TagError type_4_tag_poller_create_app(Type4TagPoller* instance) {
|
||||
UNUSED(instance);
|
||||
return Type4TagErrorNotSupported;
|
||||
Type4TagError error = Type4TagErrorNotSupported;
|
||||
|
||||
if(instance->data->platform == Type4TagPlatformMfDesfire) {
|
||||
MfDesfirePoller* mf_des = mf_desfire_poller.alloc(instance->iso14443_4a_poller);
|
||||
MfDesfireError mf_des_error;
|
||||
|
||||
do {
|
||||
// Select PICC (Card) level
|
||||
MfDesfireApplicationId picc_aid = {{0x00, 0x00, 0x00}};
|
||||
mf_des_error = mf_desfire_poller_select_application(mf_des, &picc_aid);
|
||||
if(mf_des_error != MfDesfireErrorNone) {
|
||||
error = Type4TagErrorProtocol;
|
||||
break;
|
||||
}
|
||||
|
||||
// Create NDEF application
|
||||
MfDesfireApplicationId ndef_aid = {{0x10, 0xEE, 0xEE}};
|
||||
MfDesfireKeySettings key_settings = {
|
||||
.is_master_key_changeable = true,
|
||||
.is_free_directory_list = true,
|
||||
.is_free_create_delete = true,
|
||||
.is_config_changeable = true,
|
||||
.change_key_id = 0,
|
||||
.max_keys = 1,
|
||||
.flags = 0,
|
||||
};
|
||||
mf_des_error = mf_desfire_poller_create_application(
|
||||
mf_des,
|
||||
&ndef_aid,
|
||||
&key_settings,
|
||||
TYPE_4_TAG_ISO_DF_ID,
|
||||
type_4_tag_iso_df_name,
|
||||
sizeof(type_4_tag_iso_df_name));
|
||||
if(mf_des_error != MfDesfireErrorNone) {
|
||||
if(mf_des_error != MfDesfireErrorNotPresent &&
|
||||
mf_des_error != MfDesfireErrorTimeout) {
|
||||
error = Type4TagErrorCardLocked;
|
||||
} else {
|
||||
error = Type4TagErrorProtocol;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
error = Type4TagErrorNone;
|
||||
} while(false);
|
||||
|
||||
mf_desfire_poller.free(mf_des);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
Type4TagError type_4_tag_poller_create_cc(Type4TagPoller* instance) {
|
||||
|
||||
@@ -2636,6 +2636,7 @@ Function,+,mf_desfire_get_file_settings,const MfDesfireFileSettings*,"const MfDe
|
||||
Function,+,mf_desfire_get_uid,const uint8_t*,"const MfDesfireData*, size_t*"
|
||||
Function,+,mf_desfire_is_equal,_Bool,"const MfDesfireData*, const MfDesfireData*"
|
||||
Function,+,mf_desfire_load,_Bool,"MfDesfireData*, FlipperFormat*, uint32_t"
|
||||
Function,+,mf_desfire_poller_create_application,MfDesfireError,"MfDesfirePoller*, const MfDesfireApplicationId*, const MfDesfireKeySettings*, uint16_t, const uint8_t*, uint8_t"
|
||||
Function,+,mf_desfire_poller_read_application,MfDesfireError,"MfDesfirePoller*, MfDesfireApplication*"
|
||||
Function,+,mf_desfire_poller_read_application_ids,MfDesfireError,"MfDesfirePoller*, SimpleArray*"
|
||||
Function,+,mf_desfire_poller_read_applications,MfDesfireError,"MfDesfirePoller*, const SimpleArray*, SimpleArray*"
|
||||
|
||||
|
Reference in New Issue
Block a user