1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-02-22 12:32:02 +00:00

feat(core): Introduce NFC tests into prodtest [no changelog]

This commit is contained in:
kopecdav 2025-01-31 13:28:34 +01:00 committed by tychovrahe
parent fe64689992
commit 2686b8a033
7 changed files with 1083 additions and 422 deletions

View File

@ -26,16 +26,16 @@
#define NFC_MAX_UID_LEN 10
typedef enum{
typedef enum {
NFC_POLLER_TECH_A = 0x1,
NFC_POLLER_TECH_B = 0x1 << 1 ,
NFC_POLLER_TECH_B = 0x1 << 1,
NFC_POLLER_TECH_F = 0x1 << 2,
NFC_POLLER_TECH_V = 0x1 << 3,
NFC_CARD_EMU_TECH_A = 0x1 << 4,
NFC_CARD_EMU_TECH_F = 0x1 << 5,
} nfc_tech_t ;
} nfc_tech_t;
typedef enum{
typedef enum {
NFC_DEV_TYPE_A,
NFC_DEV_TYPE_B,
NFC_DEV_TYPE_F,
@ -45,7 +45,7 @@ typedef enum{
NFC_DEV_TYPE_UNKNOWN,
} nfc_dev_type_t;
typedef enum{
typedef enum {
NFC_STATE_IDLE,
NFC_STATE_ACTIVATED,
} nfc_event_t;
@ -58,26 +58,47 @@ typedef enum {
NFC_INITIALIZATION_FAILED,
} nfc_status_t;
typedef struct{
typedef struct {
uint8_t type;
char uid[NFC_MAX_UID_LEN];
uint8_t uid_len;
}nfc_dev_info_t;
} nfc_dev_info_t;
// Initialize NFC driver including supportive RFAL middlewere
nfc_status_t nfc_init();
// Deinitialize NFC drive
nfc_status_t nfc_deinit();
// Register NFC technology (or several) to be explored by NFC state machine
// use this function before activating the state machine with nfc_activate_stm()
nfc_status_t nfc_register_tech(nfc_tech_t tech);
nfc_status_t nfc_register_event_callback(nfc_event_t event_type, void (*cb_fn)(void));
// Register event callbacks to be called with state machine, this function is
// used when user need to further interact (read/write) with the connected NFC
// device
nfc_status_t nfc_register_event_callback(nfc_event_t event_type,
void (*cb_fn)(void));
// Activate the NFC RFAL state machine which will explore the registered
// technologies State machine handles the low level NFC protocols of registered
// technologies and provide the user with the activated device information. With
// activated, user have to constantly run NFC workerwith nfc_feed_worker() to
// activly loop the state machine.
nfc_status_t nfc_activate_stm();
// Deactivate the NFC RFAL state machine (put in IDLE state).
nfc_status_t nfc_deactivate_stm();
nfc_status_t nfc_dev_read_info(nfc_dev_info_t *dev_info);
// Calls NFC RFAL worker which service the NFC statemachine exploring the
// registered technologies. this function has to be actively called in loop
// (main NFC poll function).
nfc_status_t nfc_feed_worker();
// Read the general device information of the activated NFC device.
nfc_status_t nfc_dev_read_info(nfc_dev_info_t *dev_info);
// Write the NDFE message with the trezor.io URI to the activated NFC device.
nfc_status_t nfc_def_write_ndef_uri();
#endif // TREZORHAL_NFC_H

View File

@ -0,0 +1,653 @@
/**
******************************************************************************
* @file card_emulation.c
* @author MMY Application Team
* @brief Body function to manage card emul mode
******************************************************************************
** This notice applies to any and all portions of this file
* that are not between comment pairs USER CODE BEGIN and
* USER CODE END. Other portions of this file, whether
* inserted by the user or by software development tools
* are owned by their respective copyright owners.
*
* COPYRIGHT(c) 2018 STMicroelectronics
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "card_emulation.h"
#include "rfal_nfca.h"
#include "rfal_nfcf.h"
#include "rfal_rf.h"
/** @addtogroup X-CUBE-NFC6_Applications
* @{
*/
/** @addtogroup CardEmulation
* @{
*/
/** @addtogroup CE_CardEmul
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/** @defgroup CE_CardEmul_Private_Typedef
* @{
*/
enum States {
STATE_IDLE = 0, /*!< Emulated Tag state idle */
STATE_APP_SELECTED = 1, /*!< Emulated Tag state application selected */
STATE_CC_SELECTED = 2, /*!< Emulated Tag state CCFile selected */
STATE_FID_SELECTED = 3, /*!< Emulated Tag state FileID selected */
};
/**
* @}
*/
/* Private define ------------------------------------------------------------*/
/** @defgroup CE_CardEmul_Private_Define
* @{
*/
#define NDEF_SIZE 2048 /*!< Max NDEF size emulated. Range: 0005h - 7FFFh */
#define T4T_CLA_00 0x00 /*!< CLA value for type 4 command */
#define T4T_INS_SELECT \
0xA4 /*!< INS value for select command */
#define T4T_INS_READ \
0xB0 /*!< INS value for reabbinary command */
#define T4T_INS_UPDATE \
0xD6 /*!< INS value for update command */
#define FID_CC 0xE103 /*!< File ID number for CCFile */
#define FID_NDEF 0x0001 /*!< File ID number for NDEF file */
#define T3T_BLOCK_SIZE \
0x10 /*!< Block size in Type 3 Tag */
/**
* @}
*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/** @defgroup CE_CardEmul_Private_Variables
* @{
*/
static uint8_t gNfcfNfcid[RFAL_NFCF_NFCID2_LEN];
static uint8_t ndefFile[NDEF_SIZE]; /*!< Buffer to store NDEF File */
static int8_t nState = STATE_IDLE; /*!< Type 4 tag emulation status */
static int32_t nSelectedIdx = -1; /*!< current file selected */
static int32_t nFiles = 2; /*!< Number of file emulated */
/**
* CCLEN : Indicates the size of this CC File <BR>
* T4T_VNo : Indicates the Mapping Version <BR>
* MLe high : Max R-APDU size <BR>
* MLc high : Max C-APDU size <BR>
* NDEF FCI T: Indicates the NDEF-File_Ctrl_TLV <BR>
* NDEF FCI L: The length of the V-field <BR>
* NDEF FCI V1: NDEF File Identifier <BR>
* NDEF FCI V2: NDEF File size <BR>
* NDEF FCI V3: NDEF Read AC <BR>
* NDEF FCI V4: NDEF Write AC <BR>
*/
static uint8_t ccfile[] = {
0x00,
0x0F, /* CCLEN */
0x20, /* T4T_VNo */
0x00,
0x7F, /* MLe */
0x00,
0x7F, /* MLc */
0x04, /* T */
0x06, /* L */
(FID_NDEF & 0xFF00) >> 8,
(FID_NDEF & 0x00FF), /* V1 */
(NDEF_SIZE & 0xFF00) >> 8,
(NDEF_SIZE & 0x00FF), /* V2 */
0x00, /* V3 */
0x00 /* V4 */
};
static uint32_t pdwFileSize[] = {sizeof(ccfile),
NDEF_SIZE}; /*!< Current emulated files size */
/**
* NDEF length <BR>
* NDEF Header: MB,ME,SR,Well known Type <BR>
* NDEF type length <BR>
* NDEF payload length <BR>
* NDEF Type : URI <BR>
* NDEF URI abreviation field : http://www. <BR>
* NDEF URI string : st.com/st25-demo <BR>
*/
static const uint8_t ndef_uri[] = {
0x00, 0x15, /* NDEF length */
0xD1, /* NDEF Header */
0x01, /* NDEF type length */
0x11, /* NDEF payload length */
0x55, /* NDEF Type */
0x01, /* NDEF URI abreviation field */
0x74, 0x72, 0x65, 0x7A, 0x6F, 0x72, 0x2E, 0x69, 0x6F}; /* NDEF URI string */
__WEAK const uint8_t *NdefFile = ndef_uri;
__WEAK uint32_t NdefFileLen = sizeof(ndef_uri);
/**
* Ver : Indicates the NDEF mapping version <BR>
* Nbr : Indicates the number of blocks that can be read <BR>
* Nbw : Indicates the number of blocks that can be written <BR>
* NmaxB : Indicates the maximum number of blocks available for NDEF data <BR>
* WriteFlag : Indicates whether a previous NDEF write procedure has finished or
* not <BR> RWFlag : Indicates data can be updated or not <BR> Ln : Is the size
* of the actual stored NDEF data in bytes <BR> Checksum : allows the
* Reader/Writer to check whether the Attribute Data are correct <BR>
*/
static uint8_t InformationBlock[] = {
0x10, /* Ver */
0x08, /* Nbr */
0x08, /* Nbw */
0x00, 0x0F, /* NmaxB */
0x00, 0x00, 0x00, 0x00, /* RFU */
0x00, /* WriteFlag */
0x01, /* RWFlag */
0x00, 0x00, 0x15, /* Ln */
0x00, 0x45 /* Checksum */
};
/**
* @}
*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/** @defgroup CE_CardEmul_Private_Functions
* @{
*/
/**
*****************************************************************************
* @brief Compare 2 commands supplied in parameters
*
* @param[in] cmd : pointer to the received command.
* @param[in] find : pointer to the avalaible command.
* @param[in] len : length of the available command.
*
* @retval True : Same command.
* @retval False : Different command.
*****************************************************************************
*/
static bool cmdCompare(uint8_t *cmd, uint8_t *find, uint16_t len) {
for (int i = 0; i < 20; i++) {
if (!memcmp(&cmd[i], find, len)) {
return true;
}
}
return false;
}
/**
*****************************************************************************
* @brief Manage the T4T Select answer to the reader
*
* @param[in] cmdData : pointer to the received command.
* @param[out] rspData : pointer to the answer to send.
*
* @return Answer size.
*****************************************************************************
*/
static uint16_t card_emulation_t4t_select(uint8_t *cmdData, uint8_t *rspData) {
bool success = false;
/*
* Cmd: CLA(1) | INS(1) | P1(1) | P2(1) | Lc(1) | Data(n) | [Le(1)]
* Rsp: [FCI(n)] | SW12
*
* Select App by Name NDEF: 00 A4 04 00 07 D2 76 00 00 85 01 01 00
* Select App by Name NDEF 4 ST: 00 A4 04 00 07 A0 00 00 00 03 00 00 00
* Select CC FID: 00 A4 00 0C 02 xx xx
* Select NDEF FID: 00 A4 00 0C 02 xx xx
*/
uint8_t aid[] = {0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x01};
uint8_t fidCC[] = {FID_CC >> 8, FID_CC & 0xFF};
uint8_t fidNDEF[] = {FID_NDEF >> 8, FID_NDEF & 0xFF};
uint8_t selectFileId[] = {0xA4, 0x00, 0x0C, 0x02, 0x00, 0x01};
if (cmdCompare(cmdData, aid, sizeof(aid))) { /* Select Appli */
nState = STATE_APP_SELECTED;
success = true;
} else if ((nState >= STATE_APP_SELECTED) &&
cmdCompare(cmdData, fidCC, sizeof(fidCC))) { /* Select CC */
nState = STATE_CC_SELECTED;
nSelectedIdx = 0;
success = true;
} else if ((nState >= STATE_APP_SELECTED) &&
(cmdCompare(cmdData, fidNDEF, sizeof(fidNDEF)) ||
cmdCompare(cmdData, selectFileId,
sizeof(selectFileId)))) { /* Select NDEF */
nState = STATE_FID_SELECTED;
nSelectedIdx = 1;
success = true;
} else {
nState = STATE_IDLE;
}
rspData[0] = (success ? (char)0x90 : 0x6A);
rspData[1] = (success ? (char)0x00 : 0x82);
return 2;
}
/**
*****************************************************************************
* @brief Manage the T4T Read answer to the reader
*
* @param[in] cmdData : pointer to the received command.
* @param[out] rspData : pointer to the answer to send.
* @param[in] rspDataLen : size of the answer buffer.
*
* @return Answer size.
*****************************************************************************
*/
static uint16_t card_emulation_t4t_read(uint8_t *cmdData, uint8_t *rspData,
uint16_t rspDataLen) {
/*
* Cmd: CLA(1) | INS(1) | P1(1).. offset inside file high | P2(1).. offset
* inside file high | Le(1).. nBytes to read Rsp: BytesRead | SW12
*/
unsigned short offset = (cmdData[2] << 8) | cmdData[3];
unsigned short toRead = cmdData[4];
uint8_t *ppbMemory;
if (rspDataLen < 2) {
// platformErrorHandle(); /* Must ensure appropriate buffer */
}
/* Any file selected */
if (nSelectedIdx < 0 || nSelectedIdx >= nFiles) {
rspData[0] = ((char)0x6A);
rspData[1] = ((char)0x82);
return 2;
}
/* offset + length exceed file size */
if ((unsigned long)(offset + toRead) > pdwFileSize[nSelectedIdx]) {
toRead = pdwFileSize[nSelectedIdx] - offset;
}
if (rspDataLen < (toRead + 2)) {
rspData[0] = ((char)0x6F);
rspData[1] = ((char)0x00);
return 2;
}
ppbMemory = (nSelectedIdx == 0 ? ccfile : ndefFile);
/* read data */
memcpy(rspData, &ppbMemory[offset], toRead);
rspData[toRead] = ((char)0x90);
rspData[toRead + 1] = ((char)0x00);
return toRead + 2;
}
/**
*****************************************************************************
* @brief Manage the T4T Update answer to the reader
*
* @param[in] cmdData : pointer to the received command.
* @param[in] rspData : pointer to the answer to send.
*
* @return Answer size.
*****************************************************************************
*/
static uint16_t card_emulation_t4t_update(uint8_t *cmdData, uint8_t *rspData) {
uint32_t offset = (cmdData[2] << 8) | cmdData[3];
uint32_t length = cmdData[4];
if (nSelectedIdx != 1) {
rspData[0] = ((char)0x6A);
rspData[1] = ((char)0x82);
return 2;
}
if ((unsigned long)(offset + length) > pdwFileSize[nSelectedIdx]) {
rspData[0] = ((char)0x62);
rspData[1] = ((char)0x82);
return 2;
}
memcpy((ndefFile + offset), &cmdData[5], length);
rspData[0] = ((char)0x90);
rspData[1] = ((char)0x00);
return 2;
}
/**
*****************************************************************************
* @brief Manage the T4T Read answer to the reader
*
* @param[in] cmdData : pointer to the received command.
* @param[out] rspData : pointer to the answer to send.
* @param[in] rspDataLen : size of the answer buffer.
*
* @return Answer size.
*****************************************************************************
*/
static uint16_t card_emulation_t3t_check(uint8_t *cmdData, uint8_t *rspData,
uint16_t rspDataLen) {
/*
* Cmd: cmd | NFCID2 | NoS | Service code list | NoB | Block list
* Rsp: rsp | NFCID2 | Status Flag 1 | Status Flag 2 | NoB | Block Data
*/
uint8_t *block;
uint16_t blocknb[256];
uint32_t idx = 0;
uint32_t cnt = 0;
uint32_t nbmax = 0;
/* Command response */
rspData[idx++] = RFAL_NFCF_CMD_READ_WITHOUT_ENCRYPTION + 1;
/* NFCID 2 bytes */
if (memcmp(gNfcfNfcid, &cmdData[RFAL_NFCF_LENGTH_LEN + RFAL_NFCF_CMD_LEN],
RFAL_NFCF_NFCID2_LEN) == 0) {
memcpy(&rspData[idx], &gNfcfNfcid, RFAL_NFCF_NFCID2_LEN);
idx += RFAL_NFCF_NFCID2_LEN;
} else {
/* If NFCID2 in command is different, no answer */
return 0;
}
/* Check for command errors */
if ((cmdData[10] != 1) || ((cmdData[11] != 0x09) && (cmdData[11] != 0x0B)) ||
(cmdData[13] == 0) || (cmdData[13] > InformationBlock[1])) {
rspData[idx++] = 0xFF;
rspData[idx++] = 0xFF;
return idx;
} else {
rspData[idx++] = 0x00;
rspData[idx++] = 0x00;
}
/* Verify CHECK response length */
if (rspDataLen < (11 + (cmdData[13] * T3T_BLOCK_SIZE))) {
// platformErrorHandle(); /* Must ensure appropriate buffer */
}
/* Nob */
rspData[idx++] = cmdData[13];
/* Retrieving block to read */
block = &cmdData[14];
for (cnt = 0; cnt < cmdData[13]; cnt++) {
/* TS T3T 5.6.1.5 Service Code List Order value SHALL be between 0 and NoS-1
*/
if (((*block) & 0x0F) >= cmdData[10]) {
rspData[idx - 3] = 0xFF;
rspData[idx - 2] = 0x80; /* TS T3T table 13 - proprietary value to
indicate specific error conditions.*/
return (idx - 1);
}
/* Check block list element size */
if (*block & 0x80) {
/* 2-byte Block List element */
blocknb[cnt] = *(block + 1);
block += 2;
} else {
/* 3-byte Block List element */
blocknb[cnt] = *(block + 2); /* Little Endian Format */
blocknb[cnt] <<= 8;
blocknb[cnt] |= *(block + 1);
block += 3;
}
/* Return error if Blocknb > NmaxB */
nbmax = InformationBlock[3];
nbmax = (nbmax << 8) | InformationBlock[4];
if (blocknb[cnt] > nbmax) {
rspData[idx - 3] = 0xFF;
rspData[idx - 2] = 0x70;
return (idx - 1);
}
}
for (cnt = 0; cnt < cmdData[13]; cnt++) {
if (blocknb[cnt] == 0x0000) {
/* Read information block */
memcpy(&rspData[idx], InformationBlock, sizeof(InformationBlock));
idx += sizeof(InformationBlock);
} else {
/* Read ndef block */
memcpy(&rspData[idx],
&ndefFile[2 + ((blocknb[cnt] - 1) * T3T_BLOCK_SIZE)],
T3T_BLOCK_SIZE);
idx += T3T_BLOCK_SIZE;
}
}
return idx;
}
/**
*****************************************************************************
* @brief Manage the T3T Update answer to the reader
*
* @param[in] cmdData : pointer to the received command.
* @param[in] rspData : pointer to the answer to send.
*
* @return Answer size.
*****************************************************************************
*/
static uint16_t card_emulation_t3t_update(uint8_t *cmdData, uint8_t *rspData) {
/*
* Cmd: cmd | NFCID2 | NoS | Service code list | NoB | Block list | Block Data
* Rsp: rsp | NFCID2 | Status Flag 1 | Status Flag 2
*/
uint8_t *block;
uint16_t blocknb[256];
uint32_t idx = 0;
uint32_t cnt = 0;
uint32_t nbmax = 0;
/* Command response */
rspData[idx++] = RFAL_NFCF_CMD_WRITE_WITHOUT_ENCRYPTION + 1;
/* NFCID 2 bytes */
if (memcmp(gNfcfNfcid, &cmdData[RFAL_NFCF_LENGTH_LEN + RFAL_NFCF_CMD_LEN],
RFAL_NFCF_NFCID2_LEN) == 0) {
memcpy(&rspData[idx], gNfcfNfcid, RFAL_NFCF_NFCID2_LEN);
idx += RFAL_NFCF_NFCID2_LEN;
} else {
/* If NFCID2 in command is different, no answer */
return 0;
}
/* Check for command errors */
if ((cmdData[10] != 1) || (cmdData[11] != 0x09) || (cmdData[13] == 0) ||
(cmdData[13] > InformationBlock[2])) {
rspData[idx++] = 0xFF;
rspData[idx++] = 0xFF;
return idx;
} else {
rspData[idx++] = 0x00;
rspData[idx++] = 0x00;
}
/* Retrieving block to read */
block = &cmdData[14];
for (cnt = 0; cnt < cmdData[13]; cnt++) {
/* Check block list element size */
if (*block & 0x80) {
/* 2-byte Block List element */
blocknb[cnt] = *(block + 1);
block += 2;
} else {
/* 3-byte Block List element */
blocknb[cnt] = *(block + 2); /* Little Endian Format */
blocknb[cnt] <<= 8;
blocknb[cnt] |= *(block + 1);
block += 3;
}
/* Return error if Blocknb > NmaxB */
nbmax = InformationBlock[3];
nbmax = (nbmax << 8) | InformationBlock[4];
if (blocknb[cnt] > nbmax) {
rspData[idx - 2] = 0xFF;
rspData[idx - 1] = 0x70;
return idx;
}
}
for (cnt = 0; cnt < cmdData[13]; cnt++) {
if (blocknb[cnt] == 0x0000) {
/* Write information block */
memcpy(InformationBlock, block, T3T_BLOCK_SIZE);
block += T3T_BLOCK_SIZE;
} else {
/* Read ndef block */
memcpy(&ndefFile[2 + ((blocknb[cnt] - 1) * T3T_BLOCK_SIZE)], block,
T3T_BLOCK_SIZE);
block += T3T_BLOCK_SIZE;
}
}
/* Status flag answer */
rspData[idx++] = 0x00;
rspData[idx++] = 0x00;
return idx;
}
/**
*****************************************************************************
* @brief card emulation initialize
*
* Initializes the CE mode
*
* @param[in] nfcfNfcid : The NFCID to be used in T3T CE.
*
* @return None
*****************************************************************************
*/
void card_emulation_init(uint8_t *nfcfNfcid) {
if (nfcfNfcid != NULL) {
memcpy(gNfcfNfcid, nfcfNfcid, RFAL_NFCF_NFCID2_LEN);
}
memcpy(ndefFile, (uint8_t *)NdefFile, NdefFileLen);
/* Update AIB Ln with actual NDEF length */
InformationBlock[12] = NdefFile[0];
InformationBlock[13] = NdefFile[1];
uint16_t checksum = 0;
for (int i = 0; i < 14; i++) {
checksum += InformationBlock[i];
}
InformationBlock[14] = checksum >> 8;
InformationBlock[15] = checksum & 0xFF;
}
/**
*****************************************************************************
* @brief Demo CE T4T
*
* Parses the received command and computes the response to be sent back to
* the Reader
*
* @param[in] rxData : pointer to the received command.
* @param[in] rxDataLen : length of the received command.
* @param[in] txBuf : pointer to where the response will be placed.
* @param[in] txBufLen : size of txBuf.
*
* @return Response size.
*****************************************************************************
*/
uint16_t card_emulation_t4t(uint8_t *rxData, uint16_t rxDataLen, uint8_t *txBuf,
uint16_t txBufLen) {
if ((txBuf == NULL) || (txBufLen < 2)) {
// platformErrorHandle(); /* Must ensure appropriate buffer */
return 0;
}
if ((rxData != NULL) && (rxDataLen >= 4)) {
if (rxData[0] == T4T_CLA_00) {
switch (rxData[1]) {
case T4T_INS_SELECT:
return card_emulation_t4t_select(rxData, txBuf);
case T4T_INS_READ:
return card_emulation_t4t_read(rxData, txBuf, txBufLen);
case T4T_INS_UPDATE:
return card_emulation_t4t_update(rxData, txBuf);
default:
break;
}
}
}
/* Function not supported ... */
txBuf[0] = ((char)0x68);
txBuf[1] = ((char)0x00);
return 2;
}
/**
*****************************************************************************
* @brief Demo CE T3T
*
* Parses the received command and computes the response to be sent back to
* the Reader
*
* @param[in] rxData : pointer to the received command.
* @param[in] rxDataLen : length of the received command.
* @param[in] txBuf : pointer to where the response will be placed.
* @param[in] txBufLen : size of txBuf.
*
* @return Response size.
*****************************************************************************
*/
uint16_t card_emulation_t3t(uint8_t *rxData, uint16_t rxDataLen, uint8_t *txBuf,
uint16_t txBufLen) {
if ((txBuf == NULL) || (txBufLen < 11)) {
// platformErrorHandle(); /* Must ensure appropriate buffer */
return 0;
}
if ((rxData != NULL) && (rxDataLen >= 4)) {
switch (rxData[1]) {
case RFAL_NFCF_CMD_READ_WITHOUT_ENCRYPTION:
return card_emulation_t3t_check(rxData, txBuf, txBufLen);
case RFAL_NFCF_CMD_WRITE_WITHOUT_ENCRYPTION:
return card_emulation_t3t_update(rxData, txBuf);
default:
break;
}
}
/* Function not supported ... */
txBuf[0] = ((char)0xFF);
txBuf[1] = ((char)0xFF);
return 2;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@ -0,0 +1,105 @@
/**
******************************************************************************
* @file card_emulation.h
* @author MMY Application Team
* @brief Implementation of Common CardEmulation parts
******************************************************************************
** This notice applies to any and all portions of this file
* that are not between comment pairs USER CODE BEGIN and
* USER CODE END. Other portions of this file, whether
* inserted by the user or by software development tools
* are owned by their respective copyright owners.
*
* COPYRIGHT(c) 2018 STMicroelectronics
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef DEMO_CE_H
#define DEMO_CE_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include <stdbool.h>
#include <stdint.h>
/** @addtogroup X-CUBE-NFC6_Applications
* @brief Sample applications for X-NUCLEO-NFC06A1 STM32 expansion boards.
* @{
*/
/** @addtogroup CardEmulation
* @{
*/
/** @defgroup CE_CardEmul
* @brief Card Emulation management functions
* @{
*/
/* Exported constants --------------------------------------------------------*/
/* T3T Information Block Bytes offset */
#define T3T_INFBLK_VER_OFFSET 0
#define T3T_INFBLK_NBR_OFFSET 1
#define T3T_INFBLK_NBW_OFFSET 2
#define T3T_INFBLK_NMAXB_OFFSET 3
#define T3T_INFBLK_WRITEFLAG_OFFSET 9
#define T3T_INFBLK_RWFLAG_OFFSET 10
#define T3T_INFBLK_LN_OFFSET 11
#define T3T_INFBCK_CHECKSUM_OFFSET 14
/* T3T Information Block WriteFlag values */
#define T3T_WRITEFLAG_OFF 0x00
#define T3T_WRITEFLAG_ON 0x0F
/* T3T COMMAND OFFSET */
#define T3T_CHECK_RESP_CMD_OFFSET 0
#define T3T_CHECK_RESP_NFCID2_OFFSET 1
#define T3T_CHECK_RESP_SF1_OFFSET 9
#define T3T_CHECK_RESP_SF2_OFFSET 10
#define T3T_CHECK_RESP_NOB_OFFSET 11
#define T3T_CHECK_RESP_DATA_OFFSET 12
#define T3T_UPDATE_RESP_CMD_OFFSET 0
#define T3T_UPDATE_RESP_NFCID2_OFFSET 1
#define T3T_UPDATE_RESP_SF1_OFFSET 9
#define T3T_UPDATE_RESP_SF2_OFFSET 10
/* External variables --------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
/** @defgroup CE_CardEmul_Exported_functions
* @{
*/
void card_emulation_init(uint8_t *nfcfNfcid);
uint16_t card_emulation_t3t(uint8_t *rxData, uint16_t rxDataLen, uint8_t *txBuf,
uint16_t txBufLen);
uint16_t card_emulation_t4t(uint8_t *rxData, uint16_t rxDataLen, uint8_t *txBuf,
uint16_t txBufLen);
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* DEMO_CE_H */
/******************* (C) COPYRIGHT 2018 STMicroelectronics *****END OF FILE****/

View File

@ -1,132 +1,166 @@
#include "ndef.h"
#include <stdint.h>
#include <string.h>
#include "ndef.h"
// ndef_status_t create_ndef_record_uri(uint8_t *bytearray, )
ndef_status_t parse_ndef_message(uint8_t *buffer, uint16_t buffer_len,
ndef_message_t *message) {
memset(message, 0, sizeof(ndef_message_t));
ndef_status_t parse_ndef_message(uint8_t *buffer, uint16_t buffer_len ,ndef_message_t *message){
uint16_t remaining_len = buffer_len;
// Indicate TLV header
if (*buffer == 0x3) {
buffer++;
} else {
return NDEF_ERROR; // Not a valid TLV structure
}
memset(message, 0, sizeof(ndef_message_t));
// TLV length
if (*buffer == 0xFF) {
// TLV 3 byte length format
buffer++;
message->message_total_len = (int16_t)(buffer[0] << 8 | buffer[1]);
buffer = buffer + 2;
uint16_t remaining_len = buffer_len;
} else {
message->message_total_len = *buffer;
buffer++;
}
remaining_len = message->message_total_len;
// Indicate TLV header
if(*buffer == 0x3){
buffer++;
}else{
return NDEF_ERROR; // Not a valid TLV structure
while (1) {
parse_ndef_record(buffer, remaining_len,
&(message->records[message->records_cnt]));
buffer += message->records[message->records_cnt].record_total_len;
remaining_len -= message->records[message->records_cnt].record_total_len;
message->records_cnt++;
if (message->records_cnt >= NDEF_MAX_RECORDS) {
break; // Max records reached
}
// TLV length
if(*buffer == 0xFF){
// TLV 3 byte length format
buffer++;
message->message_total_len = (int16_t) (buffer[0] << 8 | buffer[1]);
buffer = buffer + 2;
}else{
message->message_total_len = *buffer;
buffer++;
if (remaining_len == 0) {
break;
}
}
remaining_len = message->message_total_len;
// Check TLV termination character
if (*buffer != 0xFE) {
return NDEF_ERROR; // Not a valid TLV structure
}
while(1){
parse_ndef_record(buffer, remaining_len , &(message->records[message->records_cnt]));
buffer += message->records[message->records_cnt].record_total_len;
remaining_len -= message->records[message->records_cnt].record_total_len;
message->records_cnt++;
if(message->records_cnt >= NDEF_MAX_RECORDS){
break; // Max records reached
}
if(remaining_len == 0){
break;
}
}
// Check TLV termination character
if(*buffer != 0xFE){
return NDEF_ERROR; // Not a valid TLV structure
}
return NDEF_OK;
return NDEF_OK;
}
ndef_status_t parse_ndef_record(uint8_t *buffer, uint16_t len, ndef_record_t *rec){
ndef_status_t parse_ndef_record(uint8_t *buffer, uint16_t len,
ndef_record_t *rec) {
uint8_t bp = 0;
// Check if there is enough items to cover first part of the header revelaing record length
if(len < 3){
return NDEF_ERROR; // Not enough data to parse
// Check if there is enough items to cover first part of the header revelaing
// record length
if (len < 3) {
return NDEF_ERROR; // Not enough data to parse
}
// Look at first byte, parse header
memcpy(&(rec->header), buffer, 1);
bp++;
if(rec->header.tnf == 0x00 || rec->header.tnf > 0x06){
return NDEF_ERROR; // Empty or non-existing record
if (rec->header.tnf == 0x00 || rec->header.tnf > 0x06) {
return NDEF_ERROR; // Empty or non-existing record
}
rec->type_length = buffer[bp++];
if(rec->header.sr){
if (rec->header.sr) {
rec->payload_length = buffer[bp++];
}else{
} else {
memcpy(&(rec->payload_length), buffer + bp, 4);
bp += 4;
}
if(rec->header.il){
if (rec->header.il) {
rec->id_length = buffer[bp++];
}else{
} else {
// ID length ommited
rec->id_length = 0;
}
if(rec->type_length > 0){
if (rec->type_length > 0) {
memcpy(&(rec->type), buffer + bp, rec->type_length);
bp += rec->type_length;
}else{
} else {
// Type length ommited
rec->type = 0;
}
if(rec->id_length > 0){
if (rec->id_length > 0) {
memcpy(&(rec->id), buffer + bp, rec->id_length);
bp += rec->id_length;
}else{
} else {
// ID length ommited
rec->id = 0;
}
if(rec->payload_length > 0){
if (rec->payload_length > 0) {
memcpy(rec->payload, buffer + bp, rec->payload_length);
bp += rec->payload_length;
}else{
} else {
// Payload length ommited;
}
rec->record_total_len = bp;
return NDEF_OK;
}
uint16_t create_ndef_uri(const char *uri, uint8_t *buffer) {
*buffer = 0x3; // TLV header
buffer++;
uint16_t uri_len = strlen(uri);
// NDEF message length
*buffer = uri_len + 5; // uri + record header;
buffer++;
// ndef_record_header_t hdr = {
// .tnf = 0x01,
// .il = 0,
// .sr = 1,
// .cf = 0,
// .me = 1,
// .mb = 1,
// };
*buffer = 0xD1; // NDEF record Header
buffer++;
*buffer = 0x1; // Type length
buffer++;
*buffer = uri_len; // Payload length
buffer++;
*buffer = 0x55; // URI type
buffer++;
*buffer = 0x1; // URI abreviation
buffer++;
for (uint8_t i = 0; i < uri_len; i++) {
*buffer = uri[i];
buffer++;
}
// memcpy(buffer, uri, uri_len);
*buffer = 0xFE; // TLV termination
return uri_len + 7; // return buffer len
}

View File

@ -1,4 +1,4 @@
#include <stdint.h>
#ifndef NDEF_H
#define NDEF_H
@ -6,22 +6,21 @@
#define NDEF_MAX_RECORDS 3
#define NDEF_MAX_RECORD_PAYLOAD_BYTES 50
typedef enum{
NDEF_OK = 0,
NDEF_ERROR = 1,
typedef enum {
NDEF_OK = 0,
NDEF_ERROR = 1,
} ndef_status_t;
typedef struct{
typedef struct {
uint8_t tnf : 3;
uint8_t il : 1;
uint8_t sr : 1;
uint8_t cf : 1;
uint8_t me : 1;
uint8_t mb : 1;
}ndef_record_header_t;
uint8_t il : 1;
uint8_t sr : 1;
uint8_t cf : 1;
uint8_t me : 1;
uint8_t mb : 1;
} ndef_record_header_t;
typedef struct{
typedef struct {
ndef_record_header_t header;
uint8_t type_length;
uint32_t payload_length;
@ -30,15 +29,18 @@ typedef struct{
uint8_t id;
uint8_t payload[NDEF_MAX_RECORD_PAYLOAD_BYTES];
uint16_t record_total_len;
}ndef_record_t;
} ndef_record_t;
typedef struct{
uint32_t message_total_len;
uint8_t records_cnt;
ndef_record_t records[NDEF_MAX_RECORDS];
typedef struct {
uint32_t message_total_len;
uint8_t records_cnt;
ndef_record_t records[NDEF_MAX_RECORDS];
} ndef_message_t;
ndef_status_t parse_ndef_message(uint8_t *buffer, uint16_t buffer_len ,ndef_message_t *message);
ndef_status_t parse_ndef_record(uint8_t *buffer, uint16_t len, ndef_record_t *rec);
ndef_status_t parse_ndef_message(uint8_t *buffer, uint16_t buffer_len,
ndef_message_t *message);
ndef_status_t parse_ndef_record(uint8_t *buffer, uint16_t len,
ndef_record_t *rec);
uint16_t create_ndef_uri(const char *uri, uint8_t *buffer);
#endif

View File

@ -5,9 +5,10 @@
#include <trezor_rtl.h>
#include "../inc/io/nfc.h"
#include "card_emulation.h"
#include "ndef.h"
#include "nfc_internal.h"
#include "rfal_platform.h"
#include "ndef.h"
#include "../rfal/include/rfal_isoDep.h"
#include "../rfal/include/rfal_nfc.h"
@ -19,15 +20,6 @@
#include "stm32u5xx_hal.h"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-variable"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-function"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
typedef struct {
bool initialized;
// SPI driver
@ -36,8 +28,8 @@ typedef struct {
void (*nfc_irq_callback)(void);
// Event callbacks
void(*nfc_state_idle_cb)(void);
void(*nfc_state_activated_cb)(void);
void (*nfc_state_idle_cb)(void);
void (*nfc_state_activated_cb)(void);
EXTI_HandleTypeDef hEXTI;
@ -48,13 +40,13 @@ static st25r3916b_driver_t g_st25r3916b_driver = {
.initialized = false,
};
typedef struct{
typedef struct {
uint8_t UID[7];
uint8_t BCC[1];
uint8_t SYSTEM_AREA[2];
union{
union {
uint8_t CC[4];
struct{
struct {
uint8_t CC_MAGIC_NUMBER;
uint8_t CC_VERSION;
uint8_t CC_SIZE;
@ -63,76 +55,19 @@ typedef struct{
};
} nfc_device_header_t2t_t;
static void parse_tag_header(uint8_t *data, uint16_t dataLen);
// static void parse_tag_header(uint8_t *data, uint16_t dataLen);
static char *hex2Str(unsigned char *data, size_t dataLen);
/* Definition of possible states the demo state machine could have */
#define DEMO_ST_CE_NOTINIT 0 /*!< Demo State: Not initialized */
#define DEMO_ST_CE_START_DISCOVERY 1 /*!< Demo State: Start Discovery */
#define DEMO_ST_CE_DISCOVERY 2 /*!< Demo State: Discovery */
#define DEMO_ST_CE_TAG_OPERATION 3 /*!< Demo State: Discovery */
/* Definition of possible states the demo state machine could have */
#define DEMO_ST_NOTINIT 0 /*!< Demo State: Not initialized */
#define DEMO_ST_START_DISCOVERY 1 /*!< Demo State: Start Discovery */
#define DEMO_ST_DISCOVERY 2 /*!< Demo State: Discovery */
#define DEMO_NFCV_BLOCK_LEN 4 /*!< NFCV Block len */
#define DEMO_NFCV_USE_SELECT_MODE \
false /*!< NFCV demonstrate select mode */
/*
******************************************************************************
* GLOBAL DEFINES
******************************************************************************
*/
/* Definition of possible states the demo state machine could have */
#define DEMO_ST_NOTINIT 0 /*!< Demo State: Not initialized | Stopped */
#define DEMO_ST_START_DISCOVERY 1 /*!< Demo State: Start Discovery */
#define DEMO_ST_DISCOVERY 2 /*!< Demo State: Discovery */
#define DEMO_NFCV_BLOCK_LEN 4 /*!< NFCV Block len */
#define DEMO_NFCV_USE_SELECT_MODE \
false /*!< NFCV demonstrate select mode */
#define DEMO_NFCV_WRITE_TAG false /*!< NFCV demonstrate Write Single Block */
/* Definition of various Listen Mode constants */
#if defined(DEMO_LISTEN_MODE_TARGET)
#define DEMO_LM_SEL_RES \
0x40U /*!<NFC-A SEL_RES configured for the NFC-DEP protocol */
#define DEMO_LM_NFCID2_BYTE1 \
0x01U /*!<NFC-F SENSF_RES configured for the NFC-DEP protocol */
#define DEMO_LM_SC_BYTE1 \
0xFFU /*!<NFC-F System Code byte 1 */
#define DEMO_LM_SC_BYTE2 \
0xFFU /*!<NFC-F System Code byte 2 */
#define DEMO_LM_PAD0 \
0xFFU /*!<NFC-F PAD0 */
#else
#define DEMO_LM_SEL_RES \
#define LM_SEL_RES \
0x20U /*!<NFC-A SEL_RES configured for Type 4A Tag Platform */
#define DEMO_LM_NFCID2_BYTE1 \
#define LM_NFCID2_BYTE1 \
0x02U /*!<NFC-F SENSF_RES configured for Type 3 Tag Platform */
#define DEMO_LM_SC_BYTE1 \
#define LM_SC_BYTE1 \
0x12U /*!<NFC-F System Code byte 1 */
#define DEMO_LM_SC_BYTE2 \
#define LM_SC_BYTE2 \
0xFCU /*!<NFC-F System Code byte 2 */
#define DEMO_LM_PAD0 \
#define LM_PAD0 \
0x00U /*!<NFC-F PAD0 */
#endif
/*
******************************************************************************
* GLOBAL MACROS
******************************************************************************
*/
/*
******************************************************************************
* LOCAL VARIABLES
******************************************************************************
*/
/* P2P communication data */
static uint8_t NFCID3[] = {0x01, 0xFE, 0x03, 0x04, 0x05,
@ -141,113 +76,41 @@ static uint8_t GB[] = {0x46, 0x66, 0x6d, 0x01, 0x01, 0x11, 0x02,
0x02, 0x07, 0x80, 0x03, 0x02, 0x00, 0x03,
0x04, 0x01, 0x32, 0x07, 0x01, 0x03};
/* APDUs communication data */
#if RFAL_FEATURE_ISO_DEP_POLL
static uint8_t ndefSelectApp[] = {0x00, 0xA4, 0x04, 0x00, 0x07, 0xD2, 0x76,
0x00, 0x00, 0x85, 0x01, 0x01, 0x00};
static uint8_t ccSelectFile[] = {0x00, 0xA4, 0x00, 0x0C, 0x02, 0xE1, 0x03};
static uint8_t readBinary[] = {0x00, 0xB0, 0x00, 0x00, 0x0F};
/* For a Payment application a Select PPSE would be needed:
ppseSelectApp[] = { 0x00, 0xA4, 0x04, 0x00, 0x0E, 0x32, 0x50, 0x41, 0x59,
0x2E, 0x53, 0x59, 0x53, 0x2E, 0x44, 0x44, 0x46, 0x30, 0x31, 0x00 } */
#endif /* RFAL_FEATURE_ISO_DEP_POLL */
#if RFAL_FEATURE_NFC_DEP
/* P2P communication data */
static uint8_t ndefLLCPSYMM[] = {0x00, 0x00};
static uint8_t ndefInit[] = {0x05, 0x20, 0x06, 0x0F, 0x75, 0x72, 0x6E,
0x3A, 0x6E, 0x66, 0x63, 0x3A, 0x73, 0x6E,
0x3A, 0x73, 0x6E, 0x65, 0x70, 0x02, 0x02,
0x07, 0x80, 0x05, 0x01, 0x02};
static uint8_t ndefUriSTcom[] = {
0x13, 0x20, 0x00, 0x10, 0x02, 0x00, 0x00, 0x00, 0x19, 0xc1, 0x01, 0x00,
0x00, 0x00, 0x12, 0x55, 0x00, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f,
0x77, 0x77, 0x77, 0x2e, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d};
#endif /* RFAL_FEATURE_NFC_DEP */
#if RFAL_SUPPORT_CE && RFAL_FEATURE_LISTEN_MODE
#if RFAL_SUPPORT_MODE_LISTEN_NFCA
/* NFC-A CE config */
/* 4-byte UIDs with first byte 0x08 would need random number for the subsequent
* 3 bytes. 4-byte UIDs with first byte 0x*F are Fixed number, not unique, use
* for this demo 7-byte UIDs need a manufacturer ID and need to assure
* uniqueness of the rest.*/
static uint8_t ceNFCA_NFCID[] = {
0x5F, 'S', 'T', 'M'}; /* =_STM, 5F 53 54 4D NFCID1 / UID (4 bytes) */
0x1, 0x2, 0x3, 0x4}; /* =_STM, 5F 53 54 4D NFCID1 / UID (4 bytes) */
static uint8_t ceNFCA_SENS_RES[] = {0x02,
0x00}; /* SENS_RES / ATQA for 4-byte UID */
static uint8_t ceNFCA_SEL_RES = DEMO_LM_SEL_RES; /* SEL_RES / SAK */
#endif /* RFAL_SUPPORT_MODE_LISTEN_NFCA */
0x00}; /* SENS_RES / ATQA for 4-byte UID */
static uint8_t ceNFCA_SEL_RES = LM_SEL_RES; /* SEL_RES / SAK */
static uint8_t ceNFCF_nfcid2[] = {
DEMO_LM_NFCID2_BYTE1, 0xFE, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
LM_NFCID2_BYTE1, 0xFE, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
#if RFAL_SUPPORT_MODE_LISTEN_NFCF
/* NFC-F CE config */
static uint8_t ceNFCF_SC[] = {DEMO_LM_SC_BYTE1, DEMO_LM_SC_BYTE2};
static uint8_t ceNFCF_SC[] = {LM_SC_BYTE1, LM_SC_BYTE2};
static uint8_t ceNFCF_SENSF_RES[] = {
0x01, /* SENSF_RES */
0x02, 0xFE, 0x11, 0x22, 0x33,
0x44, 0x55, 0x66, /* NFCID2 */
DEMO_LM_PAD0, DEMO_LM_PAD0, 0x00, 0x00, 0x00,
0x7F, 0x7F, 0x00, /* PAD0, PAD1, MRTIcheck, MRTIupdate, PAD2
*/
0x00, 0x00}; /* RD */
#endif /* RFAL_SUPPORT_MODE_LISTEN_NFCF */
#endif /* RFAL_SUPPORT_CE && RFAL_FEATURE_LISTEN_MODE */
/*
******************************************************************************
* LOCAL VARIABLES
******************************************************************************
*/
// static void demoNotif(rfalNfcState st);
// static bool demoInit();
// static void demoCycle();
// static void demoP2P(rfalNfcDevice *nfcDev);
// static void demoAPDU(void);
// static void demoNfcv(rfalNfcvListenDevice *nfcvDev);
// static void demoNfcf(rfalNfcfListenDevice *nfcfDev);
// static void demoT2t(void);
// static void demoCE(rfalNfcDevice *nfcDev);
ReturnCode demoTransceiveBlocking(uint8_t *txBuf, uint16_t txBufSize,
uint8_t **rxBuf, uint16_t **rcvLen,
uint32_t fwt);
0x02, 0xFE, 0x11, 0x22, 0x33,
0x44, 0x55, 0x66, /* NFCID2 */
LM_PAD0, LM_PAD0, 0x00, 0x00, 0x00,
0x7F, 0x7F, 0x00, /* PAD0, PAD1, MRTIcheck, MRTIupdate, PAD2
*/
0x00, 0x00}; /* RD */
static ReturnCode nfc_transcieve_blocking(uint8_t *txBuf, uint16_t txBufSize,
uint8_t **rxBuf, uint16_t **rcvLen,
uint32_t fwt);
static void nfc_card_emulator_loop(rfalNfcDevice *nfcDev);
#define MAX_HEX_STR 4
#define MAX_HEX_STR_LENGTH 512
char hexStr[MAX_HEX_STR][MAX_HEX_STR_LENGTH];
uint8_t hexStrIdx = 0;
char *hex2Str(unsigned char *data, size_t dataLen) {
{
unsigned char *pin = data;
const char *hex = "0123456789ABCDEF";
char *pout = hexStr[hexStrIdx];
uint8_t i = 0;
uint8_t idx = hexStrIdx;
if (dataLen == 0) {
pout[0] = 0;
} else {
for (; i < dataLen - 1; ++i) {
*pout++ = hex[(*pin >> 4) & 0xF];
*pout++ = hex[(*pin++) & 0xF];
}
*pout++ = hex[(*pin >> 4) & 0xF];
*pout++ = hex[(*pin) & 0xF];
*pout = 0;
}
hexStrIdx++;
hexStrIdx %= MAX_HEX_STR;
return hexStr[idx];
}
}
nfc_status_t nfc_init() {
st25r3916b_driver_t *drv = &g_st25r3916b_driver;
@ -299,7 +162,8 @@ nfc_status_t nfc_init() {
drv->hspi.Instance = SPI_INSTANCE_3;
drv->hspi.Init.Mode = SPI_MODE_MASTER;
drv->hspi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32; // TODO: Calculate frequency precisly.
drv->hspi.Init.BaudRatePrescaler =
SPI_BAUDRATEPRESCALER_32; // TODO: Calculate frequency precisly.
drv->hspi.Init.DataSize = SPI_DATASIZE_8BIT;
drv->hspi.Init.Direction = SPI_DIRECTION_2LINES;
drv->hspi.Init.CLKPolarity = SPI_POLARITY_LOW;
@ -342,7 +206,6 @@ nfc_status_t nfc_init() {
}
nfc_status_t nfc_deinit() {
st25r3916b_driver_t *drv = &g_st25r3916b_driver;
if (!drv->initialized) {
@ -375,39 +238,30 @@ nfc_status_t nfc_deinit() {
drv->initialized = false;
return NFC_OK;
}
void rfal_callback(rfalNfcState st){
void rfal_callback(rfalNfcState st) {
st25r3916b_driver_t *drv = &g_st25r3916b_driver;
switch(st){
switch (st) {
case RFAL_NFC_STATE_IDLE:
if(drv->nfc_state_idle_cb != NULL){
if (drv->nfc_state_idle_cb != NULL) {
drv->nfc_state_idle_cb();
}
break;
case RFAL_NFC_STATE_ACTIVATED:
if(drv->nfc_state_activated_cb != NULL){
if (drv->nfc_state_activated_cb != NULL) {
drv->nfc_state_activated_cb();
// Deactivate the device imediatly after callback
rfalNfcDeactivate(RFAL_NFC_DEACTIVATE_DISCOVERY);
}
break;
default:
// State not reported
break;
}
}
nfc_status_t nfc_register_tech(nfc_tech_t tech){
nfc_status_t nfc_register_tech(nfc_tech_t tech) {
st25r3916b_driver_t *drv = &g_st25r3916b_driver;
drv->disc_params.devLimit = 1;
@ -418,7 +272,7 @@ nfc_status_t nfc_register_tech(nfc_tech_t tech){
drv->disc_params.totalDuration = 1000U;
drv->disc_params.notifyCb = rfal_callback;
if(drv->initialized == false){
if (drv->initialized == false) {
return NFC_NOT_INITIALIZED;
}
@ -428,56 +282,54 @@ nfc_status_t nfc_register_tech(nfc_tech_t tech){
// Set general discovery parameters.
if(tech & NFC_POLLER_TECH_A){
if (tech & NFC_POLLER_TECH_A) {
drv->disc_params.techs2Find |= RFAL_NFC_POLL_TECH_A;
}
if(tech & NFC_POLLER_TECH_B){
if (tech & NFC_POLLER_TECH_B) {
drv->disc_params.techs2Find |= RFAL_NFC_POLL_TECH_B;
}
if(tech & NFC_POLLER_TECH_F){
if (tech & NFC_POLLER_TECH_F) {
drv->disc_params.techs2Find |= RFAL_NFC_POLL_TECH_F;
}
if(tech & NFC_POLLER_TECH_V){
if (tech & NFC_POLLER_TECH_V) {
drv->disc_params.techs2Find |= RFAL_NFC_POLL_TECH_V;
}
if(tech & NFC_CARD_EMU_TECH_A){
memcpy(drv->disc_params.lmConfigPA.SENS_RES, ceNFCA_SENS_RES,
RFAL_LM_SENS_RES_LEN); /* Set SENS_RES / ATQA */
memcpy(drv->disc_params.lmConfigPA.nfcid, ceNFCA_NFCID,
RFAL_LM_NFCID_LEN_04); /* Set NFCID / UID */
drv->disc_params.lmConfigPA.nfcidLen =
RFAL_LM_NFCID_LEN_04; /* Set NFCID length to 4 bytes */
drv->disc_params.lmConfigPA.SEL_RES =
ceNFCA_SEL_RES; /* Set SEL_RES / SAK */
drv->disc_params.techs2Find |= RFAL_NFC_LISTEN_TECH_A;
if (tech & NFC_CARD_EMU_TECH_A) {
card_emulation_init(ceNFCF_nfcid2);
memcpy(drv->disc_params.lmConfigPA.SENS_RES, ceNFCA_SENS_RES,
RFAL_LM_SENS_RES_LEN); /* Set SENS_RES / ATQA */
memcpy(drv->disc_params.lmConfigPA.nfcid, ceNFCA_NFCID,
RFAL_LM_NFCID_LEN_04); /* Set NFCID / UID */
drv->disc_params.lmConfigPA.nfcidLen =
RFAL_LM_NFCID_LEN_04; /* Set NFCID length to 4 bytes */
drv->disc_params.lmConfigPA.SEL_RES =
ceNFCA_SEL_RES; /* Set SEL_RES / SAK */
drv->disc_params.techs2Find |= RFAL_NFC_LISTEN_TECH_A;
}
if(tech & NFC_CARD_EMU_TECH_F){
/* Set configuration for NFC-F CE */
memcpy(drv->disc_params.lmConfigPF.SC, ceNFCF_SC,
if (tech & NFC_CARD_EMU_TECH_F) {
/* Set configuration for NFC-F CE */
memcpy(drv->disc_params.lmConfigPF.SC, ceNFCF_SC,
RFAL_LM_SENSF_SC_LEN); /* Set System Code */
memcpy(&ceNFCF_SENSF_RES[RFAL_NFCF_CMD_LEN], ceNFCF_nfcid2,
memcpy(&ceNFCF_SENSF_RES[RFAL_NFCF_CMD_LEN], ceNFCF_nfcid2,
RFAL_NFCID2_LEN); /* Load NFCID2 on SENSF_RES */
memcpy(drv->disc_params.lmConfigPF.SENSF_RES, ceNFCF_SENSF_RES,
memcpy(drv->disc_params.lmConfigPF.SENSF_RES, ceNFCF_SENSF_RES,
RFAL_LM_SENSF_RES_LEN); /* Set SENSF_RES / Poll Response */
drv->disc_params.techs2Find |= RFAL_NFC_LISTEN_TECH_F;
drv->disc_params.techs2Find |= RFAL_NFC_LISTEN_TECH_F;
}
return NFC_OK;
}
nfc_status_t nfc_register_event_callback(nfc_event_t event_type, void (*cb_fn)(void)){
nfc_status_t nfc_register_event_callback(nfc_event_t event_type,
void (*cb_fn)(void)) {
st25r3916b_driver_t *drv = &g_st25r3916b_driver;
switch(event_type){
switch (event_type) {
case NFC_STATE_IDLE:
drv->nfc_state_idle_cb = cb_fn;
break;
@ -489,20 +341,16 @@ nfc_status_t nfc_register_event_callback(nfc_event_t event_type, void (*cb_fn)(v
}
return NFC_OK;
}
nfc_status_t nfc_unregister_event_callback(){
nfc_status_t nfc_unregister_event_callback() {
st25r3916b_driver_t *drv = &g_st25r3916b_driver;
drv->disc_params.notifyCb = NULL;
return NFC_OK;
}
nfc_status_t nfc_activate_stm(){
nfc_status_t nfc_activate_stm() {
st25r3916b_driver_t *drv = &g_st25r3916b_driver;
ReturnCode err;
@ -512,11 +360,9 @@ nfc_status_t nfc_activate_stm(){
}
return NFC_OK;
}
nfc_status_t nfc_deactivate_stm(){
nfc_status_t nfc_deactivate_stm() {
// In case the NFC state machine is active, deactivate to idle before
// registering a new card emulation technology.
if (rfalNfcGetState() != RFAL_NFC_STATE_IDLE) {
@ -529,15 +375,12 @@ nfc_status_t nfc_deactivate_stm(){
return NFC_OK;
}
nfc_status_t nfc_feed_worker() {
static rfalNfcDevice *nfcDevice;
rfalNfcWorker(); /* Run RFAL worker periodically */
if (rfalNfcIsDevActivated(rfalNfcGetState())) {
rfalNfcGetActiveDevice(&nfcDevice);
switch (nfcDevice->type) {
@ -546,75 +389,32 @@ nfc_status_t nfc_feed_worker() {
switch (nfcDevice->dev.nfca.type) {
case RFAL_NFCA_T1T:
vcp_println("ISO14443A/Topaz (NFC-A T1T) TAG found. UID: %s\r\n",
hex2Str(nfcDevice->nfcid, nfcDevice->nfcidLen));
break;
case RFAL_NFCA_T4T:
vcp_println("NFCA Passive ISO-DEP device found. UID: %s\r\n",
hex2Str(nfcDevice->nfcid, nfcDevice->nfcidLen));
break;
case RFAL_NFCA_T4T_NFCDEP:
case RFAL_NFCA_NFCDEP:
break;
default:
vcp_println("ISO14443A/NFC-A card found. UID: %s\r\n",
hex2Str(nfcDevice->nfcid, nfcDevice->nfcidLen));
ReturnCode err;
uint16_t rcvLen;
uint8_t blockNum = 0;
uint8_t rxBuf[16];
vcp_println("Tag ID len: %d", nfcDevice->nfcidLen);
// Read first 16 bytes (1st block)
err = rfalT2TPollerRead(0, rxBuf, sizeof(rxBuf), &rcvLen);
parse_tag_header(rxBuf, sizeof(rxBuf));
uint8_t memory_area_data[160] = {0};
for (uint8_t i = 0; i < 10; i++) {
err = rfalT2TPollerRead(4+i*4, memory_area_data+i*16, 16 , &rcvLen);
}
ndef_message_t ndef_message;
parse_ndef_message(memory_area_data, 160, &ndef_message);
break;
}
/*******************************************************************************/
case RFAL_NFC_LISTEN_TYPE_NFCB:
vcp_println("NFC TYPE B card found. UID: %s\r\n",
hex2Str(nfcDevice->nfcid, nfcDevice->nfcidLen));
break;
/*******************************************************************************/
case RFAL_NFC_LISTEN_TYPE_NFCF:
vcp_println("NFC TYPE F card found. UID: %s\r\n",
hex2Str(nfcDevice->nfcid, nfcDevice->nfcidLen));
break;
/*******************************************************************************/
case RFAL_NFC_LISTEN_TYPE_NFCV:
vcp_println("NFC TYPE V card found. UID: %s\r\n",
hex2Str(nfcDevice->nfcid, nfcDevice->nfcidLen));
break;
/*******************************************************************************/
case RFAL_NFC_LISTEN_TYPE_ST25TB:
vcp_println("ST25TB card found. UID: %s\r\n",
hex2Str(nfcDevice->nfcid, nfcDevice->nfcidLen));
break;
/*******************************************************************************/
@ -623,9 +423,25 @@ nfc_status_t nfc_feed_worker() {
break;
/*******************************************************************************/
/*******************************************************************************/
// Card emulators need to promptly respond to the reader commands, so when
// activated rfal worker is called seveal times untill back to back
// communication with the reader is completed. This may prolong the
// run_feed_worker service time compared to standard reader mode.
case RFAL_NFC_POLL_TYPE_NFCA:
break;
case RFAL_NFC_POLL_TYPE_NFCF:
if (nfcDevice->rfInterface == RFAL_NFC_INTERFACE_NFCDEP) {
// not supported yet
} else {
nfc_card_emulator_loop(nfcDevice);
}
break;
break;
break;
/*******************************************************************************/
default:
@ -633,16 +449,51 @@ nfc_status_t nfc_feed_worker() {
}
rfalNfcDeactivate(RFAL_NFC_DEACTIVATE_DISCOVERY);
}
return NFC_OK;
}
static void nfc_card_emulator_loop(rfalNfcDevice *nfcDev) {
ReturnCode err = RFAL_ERR_INTERNAL;
uint8_t *rxData;
uint16_t *rcvLen;
uint8_t txBuf[150];
uint16_t txLen;
do {
rfalNfcWorker();
switch (rfalNfcGetState()) {
case RFAL_NFC_STATE_ACTIVATED:
err = nfc_transcieve_blocking(NULL, 0, &rxData, &rcvLen, 0);
break;
case RFAL_NFC_STATE_DATAEXCHANGE:
case RFAL_NFC_STATE_DATAEXCHANGE_DONE:
txLen = ((nfcDev->type == RFAL_NFC_POLL_TYPE_NFCA)
? card_emulation_t4t(rxData, *rcvLen, txBuf, sizeof(txBuf))
: rfalConvBytesToBits(card_emulation_t3t(
rxData, rfalConvBitsToBytes(*rcvLen), txBuf,
sizeof(txBuf))));
err = nfc_transcieve_blocking(txBuf, txLen, &rxData, &rcvLen,
RFAL_FWT_NONE);
break;
case RFAL_NFC_STATE_START_DISCOVERY:
return;
case RFAL_NFC_STATE_LISTEN_SLEEP:
default:
break;
}
} while ((err == RFAL_ERR_NONE) || (err == RFAL_ERR_SLEEP_REQ));
}
nfc_status_t nfc_transceive(const uint8_t *txData, uint16_t txDataLen,
uint8_t *rxData, uint16_t *rxDataLen) {
st25r3916b_driver_t *drv = &g_st25r3916b_driver;
if (drv->initialized == false) {
@ -654,8 +505,8 @@ nfc_status_t nfc_transceive(const uint8_t *txData, uint16_t txDataLen,
}
ReturnCode err;
err = demoTransceiveBlocking((uint8_t *)txData, txDataLen, &rxData, &rxDataLen,
RFAL_FWT_NONE);
err = nfc_transcieve_blocking((uint8_t *)txData, txDataLen, &rxData,
&rxDataLen, RFAL_FWT_NONE);
if (err != RFAL_ERR_NONE) {
return NFC_ERROR;
@ -664,15 +515,24 @@ nfc_status_t nfc_transceive(const uint8_t *txData, uint16_t txDataLen,
return NFC_OK;
}
nfc_status_t nfc_def_write_ndef_uri() {
// NDEF message
uint8_t ndef_message[128] = {0};
uint16_t buffer_len = create_ndef_uri("trezor.io/", ndef_message);
for (uint8_t i = 0; i < buffer_len / 4; i++) {
rfalT2TPollerWrite(4 + i, ndef_message + i * 4);
}
return NFC_OK;
}
nfc_status_t nfc_dev_read_info(nfc_dev_info_t *dev_info) {
if (rfalNfcIsDevActivated(rfalNfcGetState())) {
rfalNfcDevice *nfcDevice;
rfalNfcGetActiveDevice(&nfcDevice);
// Resolve device type
switch (nfcDevice->type) {
case RFAL_NFC_LISTEN_TYPE_NFCA:
@ -700,7 +560,7 @@ nfc_status_t nfc_dev_read_info(nfc_dev_info_t *dev_info) {
dev_info->uid_len = nfcDevice->nfcidLen;
if(dev_info->uid_len > 10){
if (dev_info->uid_len > 10) {
// Unexpected UID length
return NFC_ERROR;
}
@ -708,69 +568,28 @@ nfc_status_t nfc_dev_read_info(nfc_dev_info_t *dev_info) {
char *uid_str = hex2Str(nfcDevice->nfcid, nfcDevice->nfcidLen);
memcpy(dev_info->uid, uid_str, nfcDevice->nfcidLen);
}else{
} else {
// No device activated
return NFC_ERROR;
}
return NFC_OK;
}
// static void parse_tag_header(uint8_t *data, uint16_t dataLen) {
// nfc_device_header_t2t_t hdr;
static void parse_tag_header(uint8_t *data, uint16_t dataLen){
// memcpy(hdr.UID, data, 3);
// hdr.BCC[0] = data[3];
// memcpy(hdr.UID + 3, data + 4, 4);
// memcpy(hdr.SYSTEM_AREA, data + 8, 2);
// memcpy(hdr.CC, data + 12, 4);
nfc_device_header_t2t_t hdr;
// }
memcpy(hdr.UID, data, 3);
hdr.BCC[0] = data[3];
memcpy(hdr.UID + 3, data+4, 4);
memcpy(hdr.SYSTEM_AREA, data+8, 2);
memcpy(hdr.CC, data+12, 4);
// vcp_println("UID: %s", hex2Str(hdr.t2t.UID, sizeof(hdr.t2t.UID)));
// vcp_println("BCC: %s (%s)", hex2Str(hdr.t2t.BCC, sizeof(hdr.t2t.BCC)), (0x88 == (hdr.t2t.UID[0] ^ hdr.t2t.UID[1] ^ hdr.t2t.UID[2] ^ hdr.t2t.BCC[0]))? " CHECKSUM PASSED" : "CHECKSUM FAILED");
// vcp_println("SYSTEM_AREA: %s", hex2Str(hdr.t2t.SYSTEM_AREA, sizeof(hdr.t2t.SYSTEM_AREA)));
// vcp_println("CC: %s", hex2Str(hdr.t2t.CC, sizeof(hdr.t2t.CC)));
// vcp_println(" -> CC_MAGIC_NUMBER: %02X", hdr.t2t.CC_MAGIC_NUMBER);
// vcp_println(" -> CC_VERSION: %02X", hdr.t2t.CC_VERSION);
// vcp_println(" -> CC_SIZE: %02X (%d bytes)", hdr.t2t.CC_SIZE, hdr.t2t.CC_SIZE*8);
// vcp_println(" -> CC_ACCESS_CONDITION: %02X", hdr.t2t.CC_ACCESS_CONDITION);
}
/*!
*****************************************************************************
* \brief Demo Blocking Transceive
*
* Helper function to send data in a blocking manner via the rfalNfc module
*
* \warning A protocol transceive handles long timeouts (several seconds),
* transmission errors and retransmissions which may lead to a long period of
* time where the MCU/CPU is blocked in this method.
* This is a demo implementation, for a non-blocking usage example please
* refer to the Examples available with RFAL
*
* \param[in] txBuf : data to be transmitted
* \param[in] txBufSize : size of the data to be transmited
* \param[out] rxData : location where the received data has been placed
* \param[out] rcvLen : number of data bytes received
* \param[in] fwt : FWT to be used (only for RF frame interface,
* otherwise use RFAL_FWT_NONE)
*
* \return RFAL_ERR_PARAM : Invalid parameters
* \return RFAL_ERR_TIMEOUT : Timeout error
* \return RFAL_ERR_FRAMING : Framing error detected
* \return RFAL_ERR_PROTO : Protocol error detected
* \return RFAL_ERR_NONE : No error, activation successful
*
*****************************************************************************
*/
ReturnCode demoTransceiveBlocking(uint8_t *txBuf, uint16_t txBufSize,
uint8_t **rxData, uint16_t **rcvLen,
uint32_t fwt) {
static ReturnCode nfc_transcieve_blocking(uint8_t *txBuf, uint16_t txBufSize,
uint8_t **rxData, uint16_t **rcvLen,
uint32_t fwt) {
ReturnCode err;
err = rfalNfcDataExchangeStart(txBuf, txBufSize, rxData, rcvLen, fwt);
@ -783,6 +602,32 @@ ReturnCode demoTransceiveBlocking(uint8_t *txBuf, uint16_t txBufSize,
return err;
}
static char *hex2Str(unsigned char *data, size_t dataLen) {
{
unsigned char *pin = data;
const char *hex = "0123456789ABCDEF";
char *pout = hexStr[hexStrIdx];
uint8_t i = 0;
uint8_t idx = hexStrIdx;
if (dataLen == 0) {
pout[0] = 0;
} else {
for (; i < dataLen - 1; ++i) {
*pout++ = hex[(*pin >> 4) & 0xF];
*pout++ = hex[(*pin++) & 0xF];
}
*pout++ = hex[(*pin >> 4) & 0xF];
*pout++ = hex[(*pin) & 0xF];
*pout = 0;
}
hexStrIdx++;
hexStrIdx %= MAX_HEX_STR;
return hexStr[idx];
}
}
HAL_StatusTypeDef nfc_spi_transmit_receive(const uint8_t *txData,
uint8_t *rxData, uint16_t length) {
st25r3916b_driver_t *drv = &g_st25r3916b_driver;

View File

@ -94,6 +94,7 @@ def configure(
if "nfc" in features_wanted:
sources += ["embed/io/nfc/st25r3916b/nfc.c"]
sources += ["embed/io/nfc/st25r3916b/ndef.c"]
sources += ["embed/io/nfc/st25r3916b/card_emulation.c"]
sources += ["embed/io/nfc/rfal/source/st25r3916/rfal_rfst25r3916.c"]
sources += ["embed/io/nfc/rfal/source/rfal_analogConfig.c"]
sources += ["embed/io/nfc/rfal/source/rfal_nfc.c"]