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

Add support for Ultralight emulation. #215

Merged
merged 60 commits into from
Jul 16, 2024
Merged
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
248f3b2
Add support for Ultralight emulation.
turbocool3r Jun 8, 2024
34eabd7
Fix stack overflow on slot init.
turbocool3r Jun 8, 2024
f7460ce
Add the remaining tags to the tag map.
turbocool3r Jun 8, 2024
4728573
Fix `CMD_INCR_CNT` value.
turbocool3r Jun 8, 2024
89dc073
Support reading and incrementing counters.
turbocool3r Jun 8, 2024
eee3666
Fix a bug that made Ultralight EV1 and NTAG unreadable.
turbocool3r Jun 8, 2024
af5670f
Respect PROT bit in the ACCESS byte.
turbocool3r Jun 9, 2024
56c4647
Make MF0/NTAG tx buffer size appropriate for large NTAG fast reads.
turbocool3r Jun 11, 2024
1e18bd6
Properly implement fast reads.
turbocool3r Jun 11, 2024
95d69b1
Proper password authentication.
turbocool3r Jun 11, 2024
8bfad8b
Small improvements to the tx buffer handling.
turbocool3r Jun 19, 2024
80a14a1
Fix factory initialization for MF0/NTAG.
turbocool3r Jun 19, 2024
59f2611
Insert some assertions and locking.
turbocool3r Jun 19, 2024
8ddf2ea
Respect access rules when reading/writing MF0/NTAG.
turbocool3r Jun 19, 2024
2acd42a
Fix maximum block size.
turbocool3r Jun 19, 2024
2447c79
Fix handling of R/O pages and CFGLCK.
turbocool3r Jun 19, 2024
41e6a70
Changelog entry.
turbocool3r Jun 19, 2024
1f1b4fd
Fix logging for GET_VERSION command.
turbocool3r Jun 29, 2024
3af3488
Add mirroring support for NTAG.
turbocool3r Jun 30, 2024
9e25b09
Fix mirroring bug.
turbocool3r Jul 2, 2024
1c14fc0
NTAG counter and access fixes.
turbocool3r Jul 2, 2024
a283795
Fix NTAG INCR_CNT command byte order.
turbocool3r Jul 2, 2024
2da6d35
Improvements to MFU / NTAG cli commands.
turbocool3r Jul 3, 2024
76b36dd
Document MF0/NTAG UID magic mode commands.
turbocool3r Jul 4, 2024
9488127
Add commands for reading and writing to/from MF0/NTAG emulator memory.
turbocool3r Jul 4, 2024
eafa14e
Add `hf mfu eview` command.
turbocool3r Jul 5, 2024
efeaf1d
Add support for VCSL command.
turbocool3r Jul 5, 2024
18d5da0
Add `hf mfu signature` command.
turbocool3r Jul 5, 2024
297cb06
Add support for custom version and signature data for MF0 / NTAG emul…
turbocool3r Jul 5, 2024
780e594
Handle VCSL command in a separate function.
turbocool3r Jul 5, 2024
94474ee
Remove the MF0ICU1 test entry in factory data initialization.
turbocool3r Jul 5, 2024
ddcffba
Fix a bug in `hf mfu signature` command.
turbocool3r Jul 6, 2024
b5d6ad8
Prevent sending NACKs when retrieving counter data for unsupported tags.
turbocool3r Jul 6, 2024
cb41662
Add support for CHECK_TEARING_EVENT command.
turbocool3r Jul 6, 2024
3ff1c78
Fix integer conversion bugs related to `nfc_tag_mf0_ntag_get_nr_pages…
turbocool3r Jul 6, 2024
1bf23cd
Make `MFUAuthArgsUnit` parse key and swap arguments automatically.
turbocool3r Jul 7, 2024
163b41b
Fix commands for r/w into UL / NTAG emulator memory.
turbocool3r Jul 7, 2024
37f2b07
Add `hf mfu eload` command.
turbocool3r Jul 7, 2024
bdcf5d5
Fix `hf mfu rdpg` not exiting when data is not properly aligned.
turbocool3r Jul 7, 2024
4aa6b3c
Fix file output in `hf mfu dump` command.
turbocool3r Jul 7, 2024
103d51c
Properly detect auth failures in `hf mfu` subcommands.
turbocool3r Jul 7, 2024
b7a6a3f
Remove amiibo-specific code.
turbocool3r Jul 7, 2024
b5259c3
Add `--type` argument to `eload` and `dump` commands.
turbocool3r Jul 8, 2024
ff58d97
Add `hf mfu esave` command.
turbocool3r Jul 8, 2024
0ce920c
Add `hf mfu ercnt/ewcnt` commands for reading and writing emulator's …
turbocool3r Jul 8, 2024
09310dc
Account for the second locking bit when checking OTP lock status.
turbocool3r Jul 9, 2024
a52bb98
Fix `hf mfu dump` command not running without file.
turbocool3r Jul 9, 2024
dd42e7e
NTAG tags refer to their only counter by index 2.
turbocool3r Jul 9, 2024
cf109f9
Detect NAKs in `hf mfu wrpg` command.
turbocool3r Jul 9, 2024
202f5d3
Fix internal MF0 / NTAG counter indexing.
turbocool3r Jul 9, 2024
607df41
Add a command to reset MF0 / NTAG unsuccessful auth counter.
turbocool3r Jul 9, 2024
3fe0a5f
Fix `hf mfu rcnt` command.
turbocool3r Jul 9, 2024
a8c2fc1
Make answers to commands on errors similar to real cards.
turbocool3r Jul 9, 2024
1e3533a
Fix unsuccessful auth attempts counting.
turbocool3r Jul 9, 2024
a428377
Make `hf mfu dump` command properly detect card size.
turbocool3r Jul 14, 2024
82c46b3
Fix a bug breaking NTAG counter access by NFC commands.
turbocool3r Jul 14, 2024
f1e2250
Add support for NTAG 210/212.
turbocool3r Jul 14, 2024
d1c9b4b
Fix `hf mfu e(r|w)cnt` commands switching device into reader mode.
turbocool3r Jul 14, 2024
384490e
Fix an old bug in `hf mfu econfig` that prevented anticollision resol…
turbocool3r Jul 15, 2024
25a1230
Fix `hf mfu econfig` not working for NTAG 210/212.
turbocool3r Jul 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
- Added support for timestamped comments in CLI via `rem`, `;`, `%` or `#` (@doegox)
- Fixed watchdog trigger during `hw factory_reset` (@doegox)
- Added PyInstaller support for CLI client (@augustozanellato)
- Added proper Mifare Ultralight (original, C, EV1) / NTAG (213, 215, 216) emulation (@turbocooler).

## [v2.0.0][2023-09-26]
- Added `hw slot nick delete` and DELETE_SLOT_TAG_NICK (@doegox)
Expand Down
32 changes: 32 additions & 0 deletions docs/protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,38 @@ Notes:
* Command: no data
* Response: no data or N bytes: `uidlen|uid[uidlen]|atqa[2]|sak|atslen|ats[atslen]`. UID, ATQA, SAK and ATS as bytes.
* CLI: cf `hw slot list`/`hf mf econfig`/`hf mfu econfig`
### 4019: MF0_NTAG_GET_UID_MAGIC_MODE
* Command: no data
* Response: 1 byte where a non-zero value indicates that UID magic mode is enabled for the current slot.
* CLI: cf `hf mfu econfig`
### 4020: MF0_NTAG_SET_UID_MAGIC_MODE
* Command: 1 byte where a non-zero value indicates that UID magic mode should be enabled for the current slot, otherwise disabled.
* Response: no data
* CLI: cf `hf mfu econfig --enable-uid-magic`/`hf mfu econfig --disable-uid-magic`
### 4021: MF0_NTAG_READ_EMU_PAGE_DATA
* Command: 2 bytes: one for first page index, one for count of pages to be read.
* Response: `4 * n` bytes where `n` is the number if pages to be read
* CLI: cf `hf mfu eview`
### 4022: MF0_NTAG_WRITE_EMU_PAGE_DATA
* Command: 2 + `n * 4` bytes: one for first page index, one for count of pages to be read, `n * 4` for `n` pages data.
* Response: no data
* CLI: unused
### 4023: MF0_NTAG_GET_VERSION_DATA
* Command: no data
* Response: 8 version data bytes.
* CLI: cf `hf mfu econfig`
### 4024: MF0_NTAG_SET_VERSION_DATA
* Command: 8 version data bytes.
* Response: no data
* CLI: cf `hf mfu econfig --set-version <hex>`
### 4025: MF0_NTAG_GET_SIGNATURE_DATA
* Command: no data
* Response: 32 signature data bytes.
* CLI: cf `hf mfu econfig`
### 4026: MF0_NTAG_SET_SIGNATURE_DATA
* Command: 32 signature data bytes.
* Response: no data
* CLI: cf `hf mfu econfig --set-signature <hex>`
### 5000: EM410X_SET_EMU_ID
* Command: 5 bytes. `id[5]`. ID as 5 bytes.
* Response: no data
Expand Down
2 changes: 1 addition & 1 deletion firmware/application/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ SRC_FILES += \
$(PROJ_DIR)/rfid/nfctag/hf/crypto1_helper.c \
$(PROJ_DIR)/rfid/nfctag/hf/nfc_14a.c \
$(PROJ_DIR)/rfid/nfctag/hf/nfc_mf1.c \
$(PROJ_DIR)/rfid/nfctag/hf/nfc_ntag.c \
$(PROJ_DIR)/rfid/nfctag/hf/nfc_mf0_ntag.c \
$(PROJ_DIR)/rfid/nfctag/lf/lf_tag_em.c \
$(PROJ_DIR)/utils/dataframe.c \
$(PROJ_DIR)/utils/delayed_reset.c \
Expand Down
119 changes: 119 additions & 0 deletions firmware/application/src/app_cmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -790,6 +790,99 @@ static data_frame_tx_t *cmd_processor_mf1_read_emu_block_data(uint16_t cmd, uint
return data_frame_make(cmd, STATUS_SUCCESS, result_length, result_buffer);
}

static data_frame_tx_t *cmd_processor_mf0_ntag_write_emu_page_data(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
uint8_t active_slot = tag_emulation_get_slot();

tag_slot_specific_type_t active_slot_tag_types;
tag_emulation_get_specific_types_by_slot(active_slot, &active_slot_tag_types);

int nr_pages = nfc_tag_mf0_ntag_get_nr_pages_by_tag_type(active_slot_tag_types.tag_hf);
// This means wrong slot type.
if (nr_pages <= 0) return data_frame_make(cmd, STATUS_INVALID_SLOT_TYPE, 0, data);

if (length < 2) return data_frame_make(cmd, STATUS_INVALID_PARAMS, 1, &nr_pages);

int page_index = data[0];
int pages_count = data[1];
int byte_length = (int)nr_pages * NFC_TAG_MF0_NTAG_DATA_SIZE;

if (pages_count == 0) return data_frame_make(cmd, STATUS_SUCCESS, 0, NULL);
else if (
(page_index >= ((int)nr_pages))
|| (pages_count > (((int)nr_pages) - page_index))
|| (((int)length - 2) < byte_length)
) {
return data_frame_make(cmd, STATUS_INVALID_PARAMS, 1, &nr_pages);
}

tag_data_buffer_t *buffer = get_buffer_by_tag_type(active_slot_tag_types.tag_hf);
nfc_tag_mf0_ntag_information_t *info = (nfc_tag_mf0_ntag_information_t *)buffer->buffer;

memcpy(&info->memory[page_index][0], &data[2], byte_length);

return data_frame_make(cmd, STATUS_SUCCESS, 0, NULL);
}

static data_frame_tx_t *cmd_processor_mf0_ntag_read_emu_page_data(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
uint8_t active_slot = tag_emulation_get_slot();

tag_slot_specific_type_t active_slot_tag_types;
tag_emulation_get_specific_types_by_slot(active_slot, &active_slot_tag_types);

int nr_pages = nfc_tag_mf0_ntag_get_nr_pages_by_tag_type(active_slot_tag_types.tag_hf);
// This means wrong slot type.
if (nr_pages <= 0) return data_frame_make(cmd, STATUS_INVALID_SLOT_TYPE, 0, data);

if (length < 2) return data_frame_make(cmd, STATUS_INVALID_PARAMS, 1, &nr_pages);

int page_index = data[0];
int pages_count = data[1];

if (pages_count == 0) return data_frame_make(cmd, STATUS_SUCCESS, 0, NULL);
else if ((page_index >= ((int)nr_pages)) || (pages_count > (((int)nr_pages) - page_index))) {
return data_frame_make(cmd, STATUS_INVALID_PARAMS, 1, &nr_pages);
}

tag_data_buffer_t *buffer = get_buffer_by_tag_type(active_slot_tag_types.tag_hf);
nfc_tag_mf0_ntag_information_t *info = (nfc_tag_mf0_ntag_information_t *)buffer->buffer;

return data_frame_make(cmd, STATUS_SUCCESS, pages_count * NFC_TAG_MF0_NTAG_DATA_SIZE, &info->memory[page_index][0]);
}

static data_frame_tx_t *cmd_processor_mf0_ntag_get_version_data(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
uint8_t *version_data = nfc_tag_mf0_ntag_get_version_data();
if (version_data == NULL) return data_frame_make(cmd, STATUS_INVALID_SLOT_TYPE, 0, NULL);

return data_frame_make(cmd, STATUS_SUCCESS, NFC_TAG_MF0_NTAG_VER_SIZE, version_data);
}

static data_frame_tx_t *cmd_processor_mf0_ntag_set_version_data(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
if (length != 8) return data_frame_make(cmd, STATUS_INVALID_PARAMS, 0, NULL);

uint8_t *version_data = nfc_tag_mf0_ntag_get_version_data();
if (version_data == NULL) return data_frame_make(cmd, STATUS_INVALID_SLOT_TYPE, 0, NULL);
memcpy(version_data, data, NFC_TAG_MF0_NTAG_VER_SIZE);

return data_frame_make(cmd, STATUS_SUCCESS, 0, NULL);
}

static data_frame_tx_t *cmd_processor_mf0_ntag_get_signature_data(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
uint8_t *signature_data = nfc_tag_mf0_ntag_get_signature_data();
if (signature_data == NULL) return data_frame_make(cmd, STATUS_INVALID_SLOT_TYPE, 0, NULL);

return data_frame_make(cmd, STATUS_SUCCESS, NFC_TAG_MF0_NTAG_SIG_SIZE, signature_data);
}

static data_frame_tx_t *cmd_processor_mf0_ntag_set_signature_data(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
if (length != NFC_TAG_MF0_NTAG_SIG_SIZE) return data_frame_make(cmd, STATUS_INVALID_PARAMS, 0, NULL);

uint8_t *signature_data = nfc_tag_mf0_ntag_get_signature_data();
if (signature_data == NULL) return data_frame_make(cmd, STATUS_INVALID_SLOT_TYPE, 0, NULL);
memcpy(signature_data, data, NFC_TAG_MF0_NTAG_SIG_SIZE);

return data_frame_make(cmd, STATUS_SUCCESS, 0, NULL);
}

static data_frame_tx_t *cmd_processor_hf14a_set_anti_coll_data(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
// uidlen[1]|uid[uidlen]|atqa[2]|sak[1]|atslen[1]|ats[atslen]
// dynamic length, so no struct
Expand Down Expand Up @@ -1026,6 +1119,24 @@ static data_frame_tx_t *after_hf_reader_run(uint16_t cmd, uint16_t status, uint1
// fct will be defined after m_data_cmd_map because we need to know its size
data_frame_tx_t *cmd_processor_get_device_capabilities(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data);

static data_frame_tx_t *cmd_processor_mf0_ntag_get_uid_mode(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
int rc = nfc_tag_mf0_ntag_get_uid_mode();

if (rc < 0) return data_frame_make(cmd, STATUS_PAR_ERR, 0, NULL);
else {
uint8_t res = rc;
return data_frame_make(cmd, STATUS_SUCCESS, 1, &res);
}
}

static data_frame_tx_t *cmd_processor_mf0_ntag_set_uid_mode(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
if (length != 1 || !nfc_tag_mf0_ntag_set_uid_mode(data[0] != 0)) {
return data_frame_make(cmd, STATUS_PAR_ERR, 0, NULL);
}

return data_frame_make(cmd, STATUS_SUCCESS, 0, NULL);
}

/**
* (cmd -> processor) function map, the map struct is:
* cmd code before process cmd processor after process
Expand Down Expand Up @@ -1109,6 +1220,14 @@ static cmd_data_map_t m_data_cmd_map[] = {
{ DATA_CMD_MF1_GET_WRITE_MODE, NULL, cmd_processor_mf1_get_write_mode, NULL },
{ DATA_CMD_MF1_SET_WRITE_MODE, NULL, cmd_processor_mf1_set_write_mode, NULL },
{ DATA_CMD_HF14A_GET_ANTI_COLL_DATA, NULL, cmd_processor_hf14a_get_anti_coll_data, NULL },
{ DATA_CMD_MF0_NTAG_GET_UID_MAGIC_MODE, NULL, cmd_processor_mf0_ntag_get_uid_mode, NULL },
{ DATA_CMD_MF0_NTAG_SET_UID_MAGIC_MODE, NULL, cmd_processor_mf0_ntag_set_uid_mode, NULL },
{ DATA_CMD_MF0_NTAG_READ_EMU_PAGE_DATA, NULL, cmd_processor_mf0_ntag_read_emu_page_data, NULL },
{ DATA_CMD_MF0_NTAG_WRITE_EMU_PAGE_DATA, NULL, cmd_processor_mf0_ntag_write_emu_page_data, NULL },
{ DATA_CMD_MF0_NTAG_GET_VERSION_DATA, NULL, cmd_processor_mf0_ntag_get_version_data, NULL },
{ DATA_CMD_MF0_NTAG_SET_VERSION_DATA, NULL, cmd_processor_mf0_ntag_set_version_data, NULL },
{ DATA_CMD_MF0_NTAG_GET_SIGNATURE_DATA, NULL, cmd_processor_mf0_ntag_get_signature_data, NULL },
{ DATA_CMD_MF0_NTAG_SET_SIGNATURE_DATA, NULL, cmd_processor_mf0_ntag_set_signature_data, NULL },

{ DATA_CMD_EM410X_SET_EMU_ID, NULL, cmd_processor_em410x_set_emu_id, NULL },
{ DATA_CMD_EM410X_GET_EMU_ID, NULL, cmd_processor_em410x_get_emu_id, NULL },
Expand Down
8 changes: 6 additions & 2 deletions firmware/application/src/app_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -653,8 +653,12 @@ static void btn_fn_copy_ic_uid(void) {

case TAG_TYPE_NTAG_213:
case TAG_TYPE_NTAG_215:
case TAG_TYPE_NTAG_216: {
nfc_tag_ntag_information_t *p_info = (nfc_tag_ntag_information_t *)buffer->buffer;
case TAG_TYPE_NTAG_216:
case TAG_TYPE_MF0ICU1:
case TAG_TYPE_MF0ICU2:
case TAG_TYPE_MF0UL11:
case TAG_TYPE_MF0UL21: {
nfc_tag_mf0_ntag_information_t *p_info = (nfc_tag_mf0_ntag_information_t *)buffer->buffer;
antres = &(p_info->res_coll);
break;
}
Expand Down
2 changes: 2 additions & 0 deletions firmware/application/src/app_status.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,6 @@
#define STATUS_NOT_IMPLEMENTED (0x69) // Calling some unrealized operations, which belongs to the missed error of the developer
#define STATUS_FLASH_WRITE_FAIL (0x70) // Flash writing failed
#define STATUS_FLASH_READ_FAIL (0x71) // Flash read failed
#define STATUS_INVALID_SLOT_TYPE (0x72) // Invalid slot type
#define STATUS_INVALID_PARAMS (0x73) // Invalid command parameters
#endif
8 changes: 8 additions & 0 deletions firmware/application/src/data_cmd.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,14 @@
#define DATA_CMD_MF1_GET_WRITE_MODE (4016)
#define DATA_CMD_MF1_SET_WRITE_MODE (4017)
#define DATA_CMD_HF14A_GET_ANTI_COLL_DATA (4018)
#define DATA_CMD_MF0_NTAG_GET_UID_MAGIC_MODE (4019)
#define DATA_CMD_MF0_NTAG_SET_UID_MAGIC_MODE (4020)
#define DATA_CMD_MF0_NTAG_READ_EMU_PAGE_DATA (4021)
#define DATA_CMD_MF0_NTAG_WRITE_EMU_PAGE_DATA (4022)
#define DATA_CMD_MF0_NTAG_GET_VERSION_DATA (4023)
#define DATA_CMD_MF0_NTAG_SET_VERSION_DATA (4024)
#define DATA_CMD_MF0_NTAG_GET_SIGNATURE_DATA (4025)
#define DATA_CMD_MF0_NTAG_SET_SIGNATURE_DATA (4026)
//
// ******************************************************************

Expand Down
1 change: 1 addition & 0 deletions firmware/application/src/rfid/nfctag/hf/nfc_14a.c
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ uint8_t nfc_tag_14a_unwrap_frame(const uint8_t *pbtFrame, const size_t szFrameBi
* @param[in] appendCrc Whether to send the byte flow, automatically send the CRC16 verification automatically
*/
void nfc_tag_14a_tx_bytes(uint8_t *data, uint32_t bytes, bool appendCrc) {
ASSERT(bytes <= MAX_NFC_TX_BUFFER_SIZE);
NFC_14A_TX_BYTE_CORE(data, bytes, appendCrc, NRF_NFCT_FRAME_DELAY_MODE_WINDOWGRID);
}

Expand Down
2 changes: 1 addition & 1 deletion firmware/application/src/rfid/nfctag/hf/nfc_14a.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

#include "tag_emulation.h"

#define MAX_NFC_RX_BUFFER_SIZE 64
#define MAX_NFC_RX_BUFFER_SIZE 257
#define MAX_NFC_TX_BUFFER_SIZE 64

#define NFC_TAG_14A_CRC_LENGTH 2
Expand Down
Loading
Loading