cancel
Showing results for 
Search instead for 
Did you mean: 

Trying to Present Read Password or Present Write Password (Fireware ST25r3911b)

Nathaniel Arzoine
Associate II

Hi,

I have downloaded en.x-cube-nfc5 project from:

st(site)/en/ecosystems/x-nucleo-nfc05a1_html

I have connected the X-NUCLEO-NFC05A1 Shield to one of my lab boards, based on STM32F103.

I managed to make the whole thing work with this example: ndef_example_read.c (see below)

I even managed to read one of my tags (NFC type 4A)

I have ST25R3911B-DISCO board too as an example

I run it with "NFC Type 4A - NDEF Message user interface"

there are two options in the supplied ST Windows software:

Present Read Password for read NDEF message

Present Write Password for write NDEF message

0693W00000YALYGQA5.png 

and with those options I can read or write my tags with a 16Bytes password length.

I need to do the same with my board (the one with STM32F103), directly connected to the ST25r3911b, and so far I can't find how to define and send those read / write passwords.

ndef_example_read.c:

#include "utils.h"

#include "rfal_nfc.h"

#include "ndef_poller.h"

#include "ndef_message.h"

#include "ndef_types_rtd.h"

#include "ndef_types_mime.h"

#define DEMO_RAW_MESSAGE_BUF_LEN   8192 /*!< raw message buffer size */

static rfalNfcDevice    *nfcDevice;

static rfalNfcDiscoverParam discParam =

{

  .compMode      = RFAL_COMPLIANCE_MODE_NFC,

  .devLimit      = 1U,

  .nfcfBR       = RFAL_BR_212,

  .ap2pBR       = RFAL_BR_424,

  .nfcid3       = NULL,

  .GB         = NULL,

  .GBLen        = 0,

  .notifyCb      = NULL,

  .totalDuration    = 1000U,

  .wakeupEnabled    = false,

  .wakeupConfigDefault = true,

  .techs2Find     = ( RFAL_NFC_POLL_TECH_A | RFAL_NFC_POLL_TECH_B | RFAL_NFC_POLL_TECH_F | RFAL_NFC_POLL_TECH_V )

};

static ndefContext     ndefCtx;

static uint8_t       rawMessageBuf[DEMO_RAW_MESSAGE_BUF_LEN];

void ndefExampleParseMessage(uint8_t* rawMsgBuf, uint32_t rawMsgLen);

void ndefExampleParseRecord(ndefRecord *record);

void ndefExamplePrintString(const uint8_t* str, uint32_t strLen);

void ndefExampleRead( void )

{

  ReturnCode err;

  uint32_t  rawMessageLen;

  /*

   * RFAL Init

   */

  err = rfalNfcInitialize();

  if( err != ERR_NONE )

  {

    platformLog("rfalNfcInitialize return %d\r\n", err);

    return;

  }

  rfalNfcDeactivate( false );

  rfalNfcDiscover( &discParam );

  /*

   * Read loop

   */

  while (1)

  {

    rfalNfcWorker();

    if( rfalNfcIsDevActivated(rfalNfcGetState()) )

    {

      /*

       * Retrieve NFC device

       */

      rfalNfcGetActiveDevice(&nfcDevice);

      /*

       * Perform NDEF Context Initialization

       */

      err = ndefPollerContextInitialization(&ndefCtx, nfcDevice);

      if( err != ERR_NONE )

      {

        platformLog("NDEF NOT DETECTED (ndefPollerContextInitialization returns %d)\r\n", err);

        return;

      }

   

      /*

       * Perform NDEF Detect procedure

       */

      err = ndefPollerNdefDetect(&ndefCtx, NULL);

      if( err != ERR_NONE )

      {

        platformLog("NDEF NOT DETECTED (ndefPollerNdefDetect returns %d)\r\n", err);

        return;

      }

      /*

       * Perform NDEF read procedure

       */

      err = ndefPollerReadRawMessage(&ndefCtx, rawMessageBuf, sizeof(rawMessageBuf), &rawMessageLen);

      if( err != ERR_NONE )

      {

        platformLog("NDEF message cannot be read (ndefPollerReadRawMessage returns %d)\r\n", err);

        return;

      }

      platformLog("NDEF Read successful\r\n");

       

      /*

       * Parse message content

       */

      ndefExampleParseMessage(rawMessageBuf, rawMessageLen);

       

      return;

    }

  }

}

1 ACCEPTED SOLUTION

Accepted Solutions
Nathaniel Arzoine
Associate II

Thank you a lot

I finished writing my code, I made a few little changes in additions to yours @Brian TIDAL_O​ :

I add 2 function call, that get the read pass arr and the write pass arr, from my code:

GetReadPassword_p();

GetWritePassword_p();

I also added:

ret = ndefT4TPollerManageAccessRight(ctx, false); // write password

at the end of the call to gives access to write too

The file ndef_t4t.c looks like that now:

/*******************************************************************************/ 

static ReturnCode ndefT4TPollerComposeVerify( rfalIsoDepApduBufFormat *cApduBuf, bool read, const uint8_t* pwd, uint8_t pwdLen, uint16_t *cApduLen )

{   

  rfalT4tCApduParam cAPDU;

  /* CLA INS P1 P2  Lc Data  Le */

  /* 00h D6h [Offset] len Data  -  */     

  cAPDU.CLA   = RFAL_T4T_CLA;

  cAPDU.INS   = 0x20;

  cAPDU.P1    = 0x00;

  cAPDU.P2    = (read ? 0x01U : 0x02U);

  cAPDU.Lc    = pwdLen;

  cAPDU.LcFlag  = true;

  cAPDU.LeFlag  = false;

  cAPDU.cApduBuf = cApduBuf;

  cAPDU.cApduLen = cApduLen;

   

  if( pwdLen > 0U )

  {

    ST_MEMCPY( cAPDU.cApduBuf->apdu, pwd, pwdLen );

  }

   

  return rfalT4TPollerComposeCAPDU( &cAPDU );

}

/*******************************************************************************/

static ReturnCode ndefT4TPollerVerify(ndefContext *ctx, bool read, const uint8_t *pwd)

{

  ReturnCode        ret;

  rfalIsoDepApduTxRxParam isoDepAPDU;

  if( (ctx == NULL) || !ndefT4TisT4TDevice(&ctx->device) )

  {

    return ERR_PARAM;

  }

   

  if( !read && (pwd == NULL) )

  {

    return ERR_PARAM;

  }

  ndefT4TInitializeIsoDepTxRxParam(ctx, &isoDepAPDU);

  ret = ndefT4TPollerComposeVerify(isoDepAPDU.txBuf, read, pwd, (pwd == NULL) ? 0x00 : 0x10, &isoDepAPDU.txBufLen);

   

  if( ret == ERR_NONE )

  {

    ret = ndefT4TTransceiveTxRx(ctx, &isoDepAPDU); 

  }

   

  return ret;

}

/*******************************************************************************/ 

static ReturnCode ndefT4TPollerManageAccessRight(ndefContext *ctx, bool read)

{

uint8_t* readpwd = GetReadPassword_p();

uint8_t* writepwd = GetWritePassword_p();

  if(read)

return ndefT4TPollerVerify(ctx, read, readpwd);  

return ndefT4TPollerVerify(ctx, read, writepwd); 

}

/*******************************************************************************/

ReturnCode ndefT4TPollerNdefDetect(ndefContext *ctx, ndefInfo *info)

{

  ReturnCode      ret;

  uint8_t*       nLen;

  uint8_t       nlenLen;

  if( info != NULL )

  {

    info->state        = NDEF_STATE_INVALID;

    info->majorVersion     = 0U;

    info->minorVersion     = 0U;

    info->areaLen       = 0U;

    info->areaAvalableSpaceLen = 0U;

    info->messageLen      = 0U;

  }

  if( (ctx == NULL) || !ndefT4TisT4TDevice(&ctx->device) )

  {

    return ERR_PARAM;

  }

  ctx->state = NDEF_STATE_INVALID;

  /* Select NDEF Tag application TS T4T v1.0 7.2.1.1 */

  ret = ndefT4TPollerSelectNdefTagApplication(ctx);

  if( ret != ERR_NONE )

  {

    /* Conclude procedure TS T4T v1.0 7.2.1.2 */

    return ret; 

  }

   

  /* TS T4T v1.0 7.2.1.3 and following */

  ret = ndefT4TReadAndParseCCFile(ctx);

  if( ret != ERR_NONE )

  {

    return ret;

  }

  nlenLen = ( ndefMajorVersion(ctx->cc.t4t.vNo) == ndefMajorVersion(NDEF_T4T_MAPPING_VERSION_3_0) ) ? NDEF_T4T_ENLEN_LEN : NDEF_T4T_NLEN_LEN;

   

  /* TS T4T v1.0 7.2.1.7 verify file READ access */

  if( !(ndefT4TIsReadAccessGranted(ctx->cc.t4t.readAccess)) )

  {

    /* Conclude procedure TS T4T v1.0 7.2.1.8 */

    return ERR_REQUEST;

  }

  /* File size need at least be enough to store NLEN or ENLEN */

  if( ctx->cc.t4t.fileSize < nlenLen)

  {

    return ERR_REQUEST;

  }

  /* Select NDEF File TS T4T v1.0 7.2.1.9 */

  ret = ndefT4TPollerSelectFile(ctx, ctx->cc.t4t.fileId);

  if( ret != ERR_NONE )

  {

    /* Conclude procedure TS T4T v1.0 7.2.1.10 */

    return ret;

  }

  /* READ Access right management */

  ret = ndefT4TPollerManageAccessRight(ctx, true); // read password

  if( ret != ERR_NONE )

  {

    return ret;

  }   

  /* Read NLEN/ENLEN TS T4T v1.0 7.2.1.11 */

  ret = ndefT4TPollerReadBinary(ctx, 0U, nlenLen);

  if( ret != ERR_NONE )

  {

    /* Conclude procedure TS T4T v1.0 7.2.1.11 */

    return ret;

  }

  nLen = ctx->subCtx.t4t.rApduBuf.apdu;

  ctx->messageLen  = (nlenLen == NDEF_T4T_ENLEN_LEN) ? GETU32(&nLen[0]) : (uint32_t)ndefBytes2Uint16(nLen[0], nLen[1]);

  ctx->messageOffset = nlenLen;

  ctx->areaLen    = ctx->cc.t4t.fileSize;

  if ( (ctx->messageLen > (ctx->cc.t4t.fileSize - nlenLen)) || ((ctx->messageLen > 0U) && (ctx->messageLen < NDEF_T4T_MIN_NLEN)) )

  {

    /* Conclude procedure TS T4T v1.0 7.2.1.11 */

    return ERR_REQUEST;

  }

   

  if( ctx->messageLen == 0U ) 

  {

    if( !(ndefT4TIsWriteAccessGranted(ctx->cc.t4t.writeAccess)) )

    {

      /* Conclude procedure TS T4T v1.0 7.2.1.11 */

      return ERR_REQUEST;

    }

    ctx->state = NDEF_STATE_INITIALIZED;

  }

  else

  {

    ctx->state = (ndefT4TIsWriteAccessGranted(ctx->cc.t4t.writeAccess)) ? NDEF_STATE_READWRITE : NDEF_STATE_READONLY;

  }

  if( info != NULL )

  {

    info->state        = ctx->state; 

    info->majorVersion     = ndefMajorVersion(ctx->cc.t4t.vNo);

    info->minorVersion     = ndefMinorVersion(ctx->cc.t4t.vNo);

    info->areaLen       = ctx->areaLen;

    info->areaAvalableSpaceLen = ctx->areaLen - ctx->messageOffset;

    info->messageLen      = ctx->messageLen;

  }

ret = ndefT4TPollerManageAccessRight(ctx, false); // write password

if( ret != ERR_NONE )

  {

    return ret;

  }

  return ERR_NONE;

}

View solution in original post

6 REPLIES 6
Brian TIDAL
ST Employee

Hi Nathanael,

you will find an rfalST25xVPollerPresentPassword() API in rfal_st25xv.c. See https://community.st.com/s/question/0D53W000004m5e4SAA/can-anyone-provide-an-example-of-api-rfalst25xvpollerreadmessage for a code example.

Basically, you should add the call to this API before ndefPollerContextInitialization.

If this answers to your question, would you please "select as best answer". Otherwise feel free to ask more information.

Rgds

BT

In order to give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
Nathaniel Arzoine
Associate II

I already found this post and this function.

is not working, rfalST25xVPollerPresentPassword()  can get a password of more than 8 Bytes

and i need to present the ndef password of 16 Bytes

I tried to change the #define RFAL_ST25xV_PWD_LEN       8U  to 16U

but its not working

Brian TIDAL
ST Employee

Hi Nathanael,

it seems you are using a Type 4A tag. My previous answer is related to a Type V tag. Sorry for the confusion. Can you confirm you are using a ST25TA tag?

If you are using a ST25TA tag, basically you have to send a Verify command. This should be done after selecting the NDEF file. I would suggest to modify the ndefT4TPollerNdefDetect() just after the NDEF file select command (see comment /* Select NDEF File TS T4T v1.0 7.2.1.9 */ and ndefT4TPollerSelectFile() call in ndefT4TPollerNdefDetect).

As there is no API to send the verify command, you'll have to compose the APDU and to send it. I would suggest to get inspiration from one of the existing command (such as ndefT4TPollerReadBinary) to compose the APU and then you just need to use ndefT4TTransceiveTxRx to transmit it.

Feel free to share your modifications if you face some issue.

Rgds

BT

In order to give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

Hi Brian,

Thanks for your reply.

As a beginner, I assume that my knowledge is still limited.

Any chance to ask you to prepare an example code for what you suggest?

Regards,

Nathaniel

Brian TIDAL
ST Employee

Sample code sent in private message to issue a Verify command before reading the NDEF file

In order to give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
Nathaniel Arzoine
Associate II

Thank you a lot

I finished writing my code, I made a few little changes in additions to yours @Brian TIDAL_O​ :

I add 2 function call, that get the read pass arr and the write pass arr, from my code:

GetReadPassword_p();

GetWritePassword_p();

I also added:

ret = ndefT4TPollerManageAccessRight(ctx, false); // write password

at the end of the call to gives access to write too

The file ndef_t4t.c looks like that now:

/*******************************************************************************/ 

static ReturnCode ndefT4TPollerComposeVerify( rfalIsoDepApduBufFormat *cApduBuf, bool read, const uint8_t* pwd, uint8_t pwdLen, uint16_t *cApduLen )

{   

  rfalT4tCApduParam cAPDU;

  /* CLA INS P1 P2  Lc Data  Le */

  /* 00h D6h [Offset] len Data  -  */     

  cAPDU.CLA   = RFAL_T4T_CLA;

  cAPDU.INS   = 0x20;

  cAPDU.P1    = 0x00;

  cAPDU.P2    = (read ? 0x01U : 0x02U);

  cAPDU.Lc    = pwdLen;

  cAPDU.LcFlag  = true;

  cAPDU.LeFlag  = false;

  cAPDU.cApduBuf = cApduBuf;

  cAPDU.cApduLen = cApduLen;

   

  if( pwdLen > 0U )

  {

    ST_MEMCPY( cAPDU.cApduBuf->apdu, pwd, pwdLen );

  }

   

  return rfalT4TPollerComposeCAPDU( &cAPDU );

}

/*******************************************************************************/

static ReturnCode ndefT4TPollerVerify(ndefContext *ctx, bool read, const uint8_t *pwd)

{

  ReturnCode        ret;

  rfalIsoDepApduTxRxParam isoDepAPDU;

  if( (ctx == NULL) || !ndefT4TisT4TDevice(&ctx->device) )

  {

    return ERR_PARAM;

  }

   

  if( !read && (pwd == NULL) )

  {

    return ERR_PARAM;

  }

  ndefT4TInitializeIsoDepTxRxParam(ctx, &isoDepAPDU);

  ret = ndefT4TPollerComposeVerify(isoDepAPDU.txBuf, read, pwd, (pwd == NULL) ? 0x00 : 0x10, &isoDepAPDU.txBufLen);

   

  if( ret == ERR_NONE )

  {

    ret = ndefT4TTransceiveTxRx(ctx, &isoDepAPDU); 

  }

   

  return ret;

}

/*******************************************************************************/ 

static ReturnCode ndefT4TPollerManageAccessRight(ndefContext *ctx, bool read)

{

uint8_t* readpwd = GetReadPassword_p();

uint8_t* writepwd = GetWritePassword_p();

  if(read)

return ndefT4TPollerVerify(ctx, read, readpwd);  

return ndefT4TPollerVerify(ctx, read, writepwd); 

}

/*******************************************************************************/

ReturnCode ndefT4TPollerNdefDetect(ndefContext *ctx, ndefInfo *info)

{

  ReturnCode      ret;

  uint8_t*       nLen;

  uint8_t       nlenLen;

  if( info != NULL )

  {

    info->state        = NDEF_STATE_INVALID;

    info->majorVersion     = 0U;

    info->minorVersion     = 0U;

    info->areaLen       = 0U;

    info->areaAvalableSpaceLen = 0U;

    info->messageLen      = 0U;

  }

  if( (ctx == NULL) || !ndefT4TisT4TDevice(&ctx->device) )

  {

    return ERR_PARAM;

  }

  ctx->state = NDEF_STATE_INVALID;

  /* Select NDEF Tag application TS T4T v1.0 7.2.1.1 */

  ret = ndefT4TPollerSelectNdefTagApplication(ctx);

  if( ret != ERR_NONE )

  {

    /* Conclude procedure TS T4T v1.0 7.2.1.2 */

    return ret; 

  }

   

  /* TS T4T v1.0 7.2.1.3 and following */

  ret = ndefT4TReadAndParseCCFile(ctx);

  if( ret != ERR_NONE )

  {

    return ret;

  }

  nlenLen = ( ndefMajorVersion(ctx->cc.t4t.vNo) == ndefMajorVersion(NDEF_T4T_MAPPING_VERSION_3_0) ) ? NDEF_T4T_ENLEN_LEN : NDEF_T4T_NLEN_LEN;

   

  /* TS T4T v1.0 7.2.1.7 verify file READ access */

  if( !(ndefT4TIsReadAccessGranted(ctx->cc.t4t.readAccess)) )

  {

    /* Conclude procedure TS T4T v1.0 7.2.1.8 */

    return ERR_REQUEST;

  }

  /* File size need at least be enough to store NLEN or ENLEN */

  if( ctx->cc.t4t.fileSize < nlenLen)

  {

    return ERR_REQUEST;

  }

  /* Select NDEF File TS T4T v1.0 7.2.1.9 */

  ret = ndefT4TPollerSelectFile(ctx, ctx->cc.t4t.fileId);

  if( ret != ERR_NONE )

  {

    /* Conclude procedure TS T4T v1.0 7.2.1.10 */

    return ret;

  }

  /* READ Access right management */

  ret = ndefT4TPollerManageAccessRight(ctx, true); // read password

  if( ret != ERR_NONE )

  {

    return ret;

  }   

  /* Read NLEN/ENLEN TS T4T v1.0 7.2.1.11 */

  ret = ndefT4TPollerReadBinary(ctx, 0U, nlenLen);

  if( ret != ERR_NONE )

  {

    /* Conclude procedure TS T4T v1.0 7.2.1.11 */

    return ret;

  }

  nLen = ctx->subCtx.t4t.rApduBuf.apdu;

  ctx->messageLen  = (nlenLen == NDEF_T4T_ENLEN_LEN) ? GETU32(&nLen[0]) : (uint32_t)ndefBytes2Uint16(nLen[0], nLen[1]);

  ctx->messageOffset = nlenLen;

  ctx->areaLen    = ctx->cc.t4t.fileSize;

  if ( (ctx->messageLen > (ctx->cc.t4t.fileSize - nlenLen)) || ((ctx->messageLen > 0U) && (ctx->messageLen < NDEF_T4T_MIN_NLEN)) )

  {

    /* Conclude procedure TS T4T v1.0 7.2.1.11 */

    return ERR_REQUEST;

  }

   

  if( ctx->messageLen == 0U ) 

  {

    if( !(ndefT4TIsWriteAccessGranted(ctx->cc.t4t.writeAccess)) )

    {

      /* Conclude procedure TS T4T v1.0 7.2.1.11 */

      return ERR_REQUEST;

    }

    ctx->state = NDEF_STATE_INITIALIZED;

  }

  else

  {

    ctx->state = (ndefT4TIsWriteAccessGranted(ctx->cc.t4t.writeAccess)) ? NDEF_STATE_READWRITE : NDEF_STATE_READONLY;

  }

  if( info != NULL )

  {

    info->state        = ctx->state; 

    info->majorVersion     = ndefMajorVersion(ctx->cc.t4t.vNo);

    info->minorVersion     = ndefMinorVersion(ctx->cc.t4t.vNo);

    info->areaLen       = ctx->areaLen;

    info->areaAvalableSpaceLen = ctx->areaLen - ctx->messageOffset;

    info->messageLen      = ctx->messageLen;

  }

ret = ndefT4TPollerManageAccessRight(ctx, false); // write password

if( ret != ERR_NONE )

  {

    return ret;

  }

  return ERR_NONE;

}