mirror of
https://github.com/RfidResearchGroup/ChameleonUltra.git
synced 2026-05-12 11:22:59 -07:00
Merge pull request #314 from dogty/main
Fixed FAST_READ command and handling of dynamic and static locks for …
This commit is contained in:
@@ -3,6 +3,9 @@ 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]
|
||||
- Fix for FAST_READ command for nfc - mf0 tags
|
||||
- Rewrite of the dynamic and static locks logic for NTAG213, NTAG215 and NTAG216; we shouldn't take into account the block lock bits
|
||||
- Fixed an issue where we wouldn't be able to change CFG0 and CFG1 for NTAG213, NTAG215 and NTG216 once a password was added even if the cfg bit was reset.
|
||||
- Fix for static nested key recovery (@jekkos)
|
||||
- Fix LEDs being stuck on after battery check (@suut)
|
||||
- Add TCP support for the CLI (@suut)
|
||||
|
||||
@@ -400,6 +400,15 @@ void nfc_tag_14a_data_process(uint8_t *p_data) {
|
||||
m_tag_state_14a = NFC_TAG_STATE_14A_IDLE;
|
||||
}
|
||||
return;
|
||||
case NFC_TAG_14A_CMD_REQA:
|
||||
case NFC_TAG_14A_CMD_WUPA:
|
||||
// Reader is re-sending REQA/WUPA while in READY state
|
||||
// This can happen if reader retries or if frame was received incorrectly
|
||||
// Respond with ATQA again and stay in READY state
|
||||
if (auto_coll_res != NULL) {
|
||||
nfc_tag_14a_tx_bytes(auto_coll_res->atqa, 2, false);
|
||||
}
|
||||
return;
|
||||
default: {
|
||||
// After receiving the wrong level instruction, directly reset the status machine
|
||||
NRF_LOG_INFO("[MFEMUL_SELECT] Incorrect cascade level received: %02x", p_data[0]);
|
||||
|
||||
@@ -675,29 +675,49 @@ static void handle_fast_read_command(uint8_t block_num, uint8_t end_block_num) {
|
||||
|
||||
int block_max = get_block_max_by_tag_type(m_tag_type, true);
|
||||
|
||||
if (block_num >= end_block_num || end_block_num >= block_max) {
|
||||
if (block_num > end_block_num || end_block_num >= block_max) {
|
||||
nfc_tag_14a_tx_nbit(NAK_INVALID_OPERATION_TBV, 4);
|
||||
return;
|
||||
}
|
||||
|
||||
NRF_LOG_INFO("HANDLING FAST READ %02x %02x", block_num, end_block_num);
|
||||
|
||||
handle_any_read(block_num, end_block_num - block_num, block_max);
|
||||
// FAST_READ is inclusive: read from block_num to end_block_num (both included)
|
||||
handle_any_read(block_num, end_block_num - block_num + 1, block_max);
|
||||
}
|
||||
|
||||
static bool check_ro_lock_on_page(int block_num) {
|
||||
if (block_num < 3) return true;
|
||||
else if (block_num == 3) return (m_tag_information->memory[2][2] & 9) != 0; // bits 0 and 3
|
||||
else if (block_num <= MF0ICU1_PAGES) {
|
||||
else if (block_num == 3) {
|
||||
switch (m_tag_type) {
|
||||
case TAG_TYPE_NTAG_213:
|
||||
case TAG_TYPE_NTAG_215:
|
||||
case TAG_TYPE_NTAG_216:
|
||||
//page 3 can be locked or not independant of BL CC bit
|
||||
//the BL bit only freezes the lock bytes !
|
||||
return (m_tag_information->memory[2][2] & 8) != 0;
|
||||
default:
|
||||
return (m_tag_information->memory[2][2] & 9) != 0;
|
||||
}
|
||||
// bits 0 and 3
|
||||
} else if (block_num <= MF0ICU1_PAGES) {
|
||||
bool locked = false;
|
||||
switch (m_tag_type) {
|
||||
case TAG_TYPE_NTAG_213:
|
||||
case TAG_TYPE_NTAG_215:
|
||||
case TAG_TYPE_NTAG_216:
|
||||
// pages can be locked or not independant of BL bits
|
||||
//the BL bits only freezes the lock bytes !
|
||||
uint16_t lock_bits = *(uint16_t *)&m_tag_information->memory[2][2];
|
||||
return ((lock_bits >> block_num) & 0x01) == 1;
|
||||
default:
|
||||
// check block locking bits
|
||||
if (block_num <= 9) locked |= (m_tag_information->memory[2][2] & 2) == 2;
|
||||
else locked |= (m_tag_information->memory[2][2] & 4) == 4;
|
||||
|
||||
// check block locking bits
|
||||
if (block_num <= 9) locked |= (m_tag_information->memory[2][2] & 2) == 2;
|
||||
else locked |= (m_tag_information->memory[2][2] & 4) == 4;
|
||||
locked |= (((*(uint16_t *)&m_tag_information->memory[2][2]) >> block_num) & 1) == 1;
|
||||
|
||||
locked |= (((*(uint16_t *)&m_tag_information->memory[2][2]) >> block_num) & 1) == 1;
|
||||
|
||||
return locked;
|
||||
return locked;
|
||||
}
|
||||
} else {
|
||||
uint8_t *p_lock_bytes = NULL;
|
||||
int user_memory_end = 0;
|
||||
@@ -776,9 +796,43 @@ static bool check_ro_lock_on_page(int block_num) {
|
||||
|
||||
bool locked_small_range = ((lock_word >> (index / dyn_lock_bit_page_cnt)) & 1) != 0;
|
||||
bool locked_large_range = ((p_lock_bytes[2] >> (index / dyn_lock_bit_page_cnt / 2)) & 1) != 0;
|
||||
|
||||
return locked_small_range | locked_large_range;
|
||||
switch (m_tag_type) {
|
||||
case TAG_TYPE_NTAG_213:
|
||||
case TAG_TYPE_NTAG_215:
|
||||
case TAG_TYPE_NTAG_216:
|
||||
// For NTAG213/215/216: byte 2 contains block-locking bits (BL) which only freeze
|
||||
// the lock configuration. We only check the actual lock bits (L0-L15) in bytes 0-1.
|
||||
return locked_small_range;
|
||||
default:
|
||||
return locked_small_range | locked_large_range;
|
||||
}
|
||||
} else {
|
||||
//Check the block locking bits to see if we can touch the dynamic locks bytes for NTAG tags
|
||||
if(block_num == user_memory_end)
|
||||
{
|
||||
switch (m_tag_type) {
|
||||
case TAG_TYPE_NTAG_213:
|
||||
case TAG_TYPE_NTAG_215:
|
||||
case TAG_TYPE_NTAG_216:
|
||||
{
|
||||
uint8_t block_bytes = m_tag_information->memory[user_memory_end][2];
|
||||
uint16_t block_world = 0;
|
||||
|
||||
// Each bit in block_bytes maps to 2 bits in block_world
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (block_bytes & (0x01 << i)) {
|
||||
block_world |= (0x0003 << (i * 2));
|
||||
}
|
||||
}
|
||||
|
||||
p_lock_bytes = m_tag_information->memory[user_memory_end];
|
||||
uint16_t lock_word = (((uint16_t)p_lock_bytes[1]) << 8) | (uint16_t)p_lock_bytes[0];
|
||||
return (lock_word & block_world) != 0;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
// check CFGLCK bit
|
||||
int first_cfg_page = get_first_cfg_page_by_tag_type(m_tag_type);
|
||||
uint8_t access = m_tag_information->memory[first_cfg_page + CONF_ACCESS_PAGE_OFFSET][CONF_ACCESS_BYTE];
|
||||
@@ -793,7 +847,25 @@ static bool check_ro_lock_on_page(int block_num) {
|
||||
static int handle_write_command(uint8_t block_num, uint8_t *p_data) {
|
||||
int block_max = get_block_max_by_tag_type(m_tag_type, false);
|
||||
|
||||
if (block_num >= block_max) {
|
||||
bool out_of_bounds = false;
|
||||
switch (m_tag_type) {
|
||||
case TAG_TYPE_NTAG_213:
|
||||
case TAG_TYPE_NTAG_215:
|
||||
case TAG_TYPE_NTAG_216:
|
||||
int first_cfg_page = get_first_cfg_page_by_tag_type(m_tag_type);
|
||||
uint8_t cfglck = m_tag_information->memory[first_cfg_page][0] & 0x40;
|
||||
// For NTAG cards we need to check CFGLCK bit for config pages
|
||||
bool is_config_page = (block_num >= first_cfg_page) && (block_num <= first_cfg_page + 1);
|
||||
bool config_locked = (cfglck != 0) && (!m_tag_information->config.mode_uid_magic);
|
||||
bool is_beyond_user_memory = (block_num >= block_max);
|
||||
out_of_bounds = (is_beyond_user_memory && !is_config_page) || (config_locked && is_config_page);
|
||||
break;
|
||||
default:
|
||||
out_of_bounds = block_num >= block_max;
|
||||
break;
|
||||
}
|
||||
// Reject out-of-bounds writes (except config pages)
|
||||
if (out_of_bounds) {
|
||||
NRF_LOG_ERROR("Write failed: block_num %08x >= block_max %08x", block_num, block_max);
|
||||
return NAK_INVALID_OPERATION_TBV;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user