nfc: NTAG21x complete emulation (#1313)

* nfc: Refactor Mifare Ultralight feature flags
  Unify them in both reader and emulator to make handling easier
* nfc: Refactor MFUL PWD_AUTH and add AUTHLIM counter
* nfc: Add MFUL EV1 VCSL command emulation
* nfc: Enforce message size check in MFUL emulation
  Also fix READ_CNT byte order, but it's not fully working
* nfc: Add MFUL auth counter serialization
  Also fill counter on successful read from tag
* nfc: Fix MFUL INCR_CNT emulation
* nfc: Fix MFUL READ_CNT emulation
* nfc: Refactor MFUL emulation and implement full write support
* nfc: Fix Mifare Ultralight serialization
* nfc: Add MFUL OTP/CC handling
* nfc: Make sure MF0UL21 dynamic lock byte 3 also reads 0xBD
* nfc: Small MFUL refactor and fix CFGLCK behavior
* WIP: nfc: MFUL read support with ASCII mirror and auth roll-over
  This is too complex and I don't like it
* nfc: Simplify MFUL read emulation, fix mirror range check
* nfc: Implement MFUL auth and ASCII mirror for FAST_READ
* nfc: Fix MFUL read roll-over with AUTH0 set
* nfc: Implement MFUL read counter increment
* nfc: Align ASCII mirror to NTAG21x behavior
* nfc: Handle invalid command in MFUL emulation
* nfc: Fix MFUL static lock check
* nfc: Refactor MFUL emulation to use cached config pages
* nfc: Refactor MFUL auth counter to count up instead of down
* nfc: Add missing NULL check
* WIP: nfc: Various MFUL emulation behavior tweaks
* WIP: nfc: More MFUL emulation behavior adjustments
* nfc: Match AUTHLIM emulation to NTAG21x behavior
* nfc: Fix MFUL dynamic lock emulation
* nfc: Fix typo in MFUL read counters
* nfc: Fix typo in MFUL FAST_READ emulation
* nfc: Increase emulation TX buffer size
  Enough space for if someone requests FAST_READ of all pages of an NTAG
* nfc: Fix MFUL negative verification counter overflow
* nfc: Change auth counter kv name
* nfc: Fix NTAG I2C FAST_READ emulation
* nfc: Fix NTAG21x config reload behavior

Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
Yukai Li
2022-06-21 09:04:35 -06:00
committed by GitHub
parent 88facf20c1
commit 556af0b82b
5 changed files with 957 additions and 327 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -22,6 +22,10 @@
#define MF_UL_READ_VCSL (0x4B)
#define MF_UL_SECTOR_SELECT (0xC2)
#define MF_UL_ACK (0xa)
#define MF_UL_NAK_INVALID_ARGUMENT (0x0)
#define MF_UL_NAK_AUTHLIM_REACHED (0x4)
typedef enum {
MfUltralightTypeUnknown,
MfUltralightTypeUL11,
@@ -38,6 +42,31 @@ typedef enum {
MfUltralightTypeNum,
} MfUltralightType;
typedef enum {
MfUltralightSupportNone = 0,
MfUltralightSupportFastRead = 1 << 0,
MfUltralightSupportTearingFlags = 1 << 1,
MfUltralightSupportReadCounter = 1 << 2,
MfUltralightSupportIncrCounter = 1 << 3,
MfUltralightSupportSignature = 1 << 4,
MfUltralightSupportFastWrite = 1 << 5,
MfUltralightSupportCompatWrite = 1 << 6,
MfUltralightSupportAuth = 1 << 7,
MfUltralightSupportVcsl = 1 << 8,
MfUltralightSupportSectorSelect = 1 << 9,
// NTAG21x only has counter 2
MfUltralightSupportSingleCounter = 1 << 10,
// ASCII mirror is not a command, but handy to have as a flag
MfUltralightSupportAsciiMirror = 1 << 11,
} MfUltralightFeatures;
typedef enum {
MfUltralightMirrorNone,
MfUltralightMirrorUid,
MfUltralightMirrorCounter,
MfUltralightMirrorUidCounter,
} MfUltralightMirrorConf;
typedef struct {
uint8_t header;
uint8_t vendor_id;
@@ -65,38 +94,76 @@ typedef struct {
uint8_t signature[32];
uint32_t counter[3];
uint8_t tearing[3];
uint16_t curr_authlim;
uint16_t data_size;
uint8_t data[MF_UL_MAX_DUMP_SIZE];
} MfUltralightData;
typedef struct {
uint8_t pwd[4];
typedef struct __attribute__((packed)) {
union {
uint8_t raw[4];
uint32_t value;
} pwd;
union {
uint8_t raw[2];
uint16_t value;
} pack;
} MfUltralightAuth;
// Common configuration pages for MFUL EV1, NTAG21x, and NTAG I2C Plus
typedef struct __attribute__((packed)) {
union {
uint8_t value;
struct {
uint8_t rfui1 : 2;
bool strg_mod_en : 1;
bool rfui2 : 1;
uint8_t mirror_byte : 2;
MfUltralightMirrorConf mirror_conf : 2;
};
} mirror;
uint8_t rfui1;
uint8_t mirror_page;
uint8_t auth0;
union {
uint8_t value;
struct {
uint8_t authlim : 3;
bool nfc_cnt_pwd_prot : 1;
bool nfc_cnt_en : 1;
bool nfc_dis_sec1 : 1; // NTAG I2C Plus only
bool cfglck : 1;
bool prot : 1;
};
} access;
uint8_t vctid;
uint8_t rfui2[2];
MfUltralightAuth auth_data;
uint8_t rfui3[2];
} MfUltralightConfigPages;
typedef struct {
uint16_t pages_to_read;
int16_t pages_read;
bool support_fast_read;
bool support_tearing_flags;
bool support_counters;
bool support_signature;
MfUltralightFeatures supported_features;
} MfUltralightReader;
typedef struct {
MfUltralightData data;
bool support_fast_read;
MfUltralightConfigPages* config;
// Most config values don't apply until power cycle, so cache config pages
// for correct behavior
MfUltralightConfigPages config_cache;
MfUltralightFeatures supported_features;
uint16_t page_num;
bool data_changed;
bool comp_write_cmd_started;
uint8_t comp_write_page_addr;
MfUltralightAuth* auth_data;
bool auth_success;
uint8_t curr_sector;
bool sector_select_cmd_started;
bool ntag_i2c_plus_sector3_lockout;
bool read_counter_incremented;
} MfUltralightEmulator;
bool mf_ul_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK);
@@ -127,6 +194,8 @@ bool mf_ul_read_card(
MfUltralightReader* reader,
MfUltralightData* data);
void mf_ul_reset_emulation(MfUltralightEmulator* emulator, bool is_power_cycle);
void mf_ul_prepare_emulation(MfUltralightEmulator* emulator, MfUltralightData* data);
bool mf_ul_prepare_emulation_response(