399 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			399 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
 | 
						|
/******************************************************************************
 | 
						|
  * \attention
 | 
						|
  *
 | 
						|
  * <h2><center>© COPYRIGHT 2020 STMicroelectronics</center></h2>
 | 
						|
  *
 | 
						|
  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
 | 
						|
  * You may not use this file except in compliance with the License.
 | 
						|
  * You may obtain a copy of the License at:
 | 
						|
  *
 | 
						|
  *        www.st.com/myliberty
 | 
						|
  *
 | 
						|
  * Unless required by applicable law or agreed to in writing, software 
 | 
						|
  * distributed under the License is distributed on an "AS IS" BASIS, 
 | 
						|
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
 | 
						|
  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
 | 
						|
  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
 | 
						|
  * See the License for the specific language governing permissions and
 | 
						|
  * limitations under the License.
 | 
						|
  *
 | 
						|
******************************************************************************/
 | 
						|
 | 
						|
/*
 | 
						|
 *      PROJECT:   ST25R391x firmware
 | 
						|
 *      Revision:
 | 
						|
 *      LANGUAGE:  ISO C99
 | 
						|
 */
 | 
						|
 | 
						|
/*! \file rfal_t4t.h
 | 
						|
 *
 | 
						|
 *  \author Gustavo Patricio
 | 
						|
 *
 | 
						|
 *  \brief Provides convenience methods and definitions for T4T (ISO7816-4)
 | 
						|
 *  
 | 
						|
 *  This module provides an interface to exchange T4T APDUs according to 
 | 
						|
 *  NFC Forum T4T and ISO7816-4
 | 
						|
 *  
 | 
						|
 *  This implementation was based on the following specs:
 | 
						|
 *    - ISO/IEC 7816-4  3rd Edition 2013-04-15
 | 
						|
 *    - NFC Forum T4T Technical Specification 1.0 2017-08-28
 | 
						|
 *  
 | 
						|
 */
 | 
						|
 | 
						|
/*
 | 
						|
 ******************************************************************************
 | 
						|
 * INCLUDES
 | 
						|
 ******************************************************************************
 | 
						|
 */
 | 
						|
 #include "rfal_t4t.h"
 | 
						|
 #include "utils.h"
 | 
						|
 
 | 
						|
 /*
 | 
						|
 ******************************************************************************
 | 
						|
 * ENABLE SWITCH
 | 
						|
 ******************************************************************************
 | 
						|
 */
 | 
						|
 | 
						|
#ifndef RFAL_FEATURE_T4T
 | 
						|
    #define RFAL_FEATURE_T4T   false    /* T4T module configuration missing. Disabled by default */
 | 
						|
#endif
 | 
						|
 | 
						|
#if RFAL_FEATURE_T4T
 | 
						|
 | 
						|
 /*
 | 
						|
 ******************************************************************************
 | 
						|
 * GLOBAL DEFINES
 | 
						|
 ******************************************************************************
 | 
						|
 */
 | 
						|
#define RFAL_T4T_OFFSET_DO          0x54U        /*!< Tag value for offset BER-TLV data object          */
 | 
						|
#define RFAL_T4T_LENGTH_DO          0x03U        /*!< Len value for offset BER-TLV data object          */
 | 
						|
#define RFAL_T4T_DATA_DO            0x53U        /*!< Tag value for data BER-TLV data object            */
 | 
						|
 | 
						|
#define RFAL_T4T_MAX_LC             255U         /*!< Maximum Lc value for short Lc coding              */
 | 
						|
 /*
 | 
						|
******************************************************************************
 | 
						|
* GLOBAL TYPES
 | 
						|
******************************************************************************
 | 
						|
*/
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
******************************************************************************
 | 
						|
* GLOBAL MACROS
 | 
						|
******************************************************************************
 | 
						|
*/
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 ******************************************************************************
 | 
						|
 * LOCAL VARIABLES
 | 
						|
 ******************************************************************************
 | 
						|
 */
 | 
						|
 
 | 
						|
 
 | 
						|
/*
 | 
						|
 ******************************************************************************
 | 
						|
 * GLOBAL FUNCTIONS
 | 
						|
 ******************************************************************************
 | 
						|
 */
 | 
						|
 | 
						|
/*******************************************************************************/ 
 | 
						|
ReturnCode rfalT4TPollerComposeCAPDU( const rfalT4tCApduParam *apduParam )
 | 
						|
{
 | 
						|
    uint8_t                  hdrLen;
 | 
						|
    uint16_t                 msgIt;
 | 
						|
    
 | 
						|
    if( (apduParam == NULL) || (apduParam->cApduBuf == NULL) || (apduParam->cApduLen == NULL) )
 | 
						|
    {
 | 
						|
        return ERR_PARAM;
 | 
						|
    }
 | 
						|
    
 | 
						|
    msgIt                  = 0;
 | 
						|
    *(apduParam->cApduLen) = 0;
 | 
						|
    
 | 
						|
    /*******************************************************************************/
 | 
						|
    /* Compute Command-APDU  according to the format   T4T 1.0 5.1.2 & ISO7816-4 2013 Table 1 */
 | 
						|
    
 | 
						|
    /* Check if Data is present */
 | 
						|
    if( apduParam->LcFlag )
 | 
						|
    {
 | 
						|
        if( apduParam->Lc == 0U )
 | 
						|
        {
 | 
						|
            /* Extented field coding not supported */
 | 
						|
            return ERR_PARAM;
 | 
						|
        }
 | 
						|
        
 | 
						|
        /* Check whether requested Lc fits */
 | 
						|
        if( (uint16_t)apduParam->Lc > (uint16_t)(RFAL_FEATURE_ISO_DEP_APDU_MAX_LEN - RFAL_T4T_LE_LEN) )
 | 
						|
        {
 | 
						|
            return ERR_PARAM; /*  PRQA S  2880 # MISRA 2.1 - Unreachable code due to configuration option being set/unset  */ 
 | 
						|
        }
 | 
						|
        
 | 
						|
        /* Calculate the header length a place the data/body where it should be */
 | 
						|
        hdrLen = RFAL_T4T_MAX_CAPDU_PROLOGUE_LEN + RFAL_T4T_LC_LEN;
 | 
						|
        
 | 
						|
        /* make sure not to exceed buffer size */
 | 
						|
        if( ((uint16_t)hdrLen + (uint16_t)apduParam->Lc + (apduParam->LeFlag ? RFAL_T4T_LC_LEN : 0U)) > RFAL_FEATURE_ISO_DEP_APDU_MAX_LEN )
 | 
						|
        {
 | 
						|
            return ERR_NOMEM; /*  PRQA S  2880 # MISRA 2.1 - Unreachable code due to configuration option being set/unset */ 
 | 
						|
        }
 | 
						|
        ST_MEMMOVE( &apduParam->cApduBuf->apdu[hdrLen], apduParam->cApduBuf->apdu, apduParam->Lc );
 | 
						|
    }
 | 
						|
    
 | 
						|
    /* Prepend the ADPDU's header */
 | 
						|
    apduParam->cApduBuf->apdu[msgIt++] = apduParam->CLA;
 | 
						|
    apduParam->cApduBuf->apdu[msgIt++] = apduParam->INS;
 | 
						|
    apduParam->cApduBuf->apdu[msgIt++] = apduParam->P1;
 | 
						|
    apduParam->cApduBuf->apdu[msgIt++] = apduParam->P2;
 | 
						|
    
 | 
						|
    
 | 
						|
    /* Check if Data field length is to be added */
 | 
						|
    if( apduParam->LcFlag )
 | 
						|
    {
 | 
						|
        apduParam->cApduBuf->apdu[msgIt++] = apduParam->Lc;
 | 
						|
        msgIt += apduParam->Lc;
 | 
						|
    }
 | 
						|
    
 | 
						|
    /* Check if Expected Response Length is to be added */
 | 
						|
    if( apduParam->LeFlag )
 | 
						|
    {
 | 
						|
        apduParam->cApduBuf->apdu[msgIt++] = apduParam->Le;
 | 
						|
    }
 | 
						|
    
 | 
						|
    *(apduParam->cApduLen) = msgIt;
 | 
						|
    
 | 
						|
    return ERR_NONE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*******************************************************************************/
 | 
						|
ReturnCode rfalT4TPollerParseRAPDU( rfalT4tRApduParam *apduParam )
 | 
						|
{
 | 
						|
    if( (apduParam == NULL) || (apduParam->rApduBuf == NULL) )
 | 
						|
    {
 | 
						|
        return ERR_PARAM;
 | 
						|
    }
 | 
						|
    
 | 
						|
    if( apduParam->rcvdLen < RFAL_T4T_MAX_RAPDU_SW1SW2_LEN )
 | 
						|
    {
 | 
						|
        return ERR_PROTO;
 | 
						|
    }
 | 
						|
 | 
						|
    apduParam->rApduBodyLen = (apduParam->rcvdLen - (uint16_t)RFAL_T4T_MAX_RAPDU_SW1SW2_LEN);
 | 
						|
    apduParam->statusWord   = GETU16( (&apduParam->rApduBuf->apdu[ apduParam->rApduBodyLen ]) );
 | 
						|
 | 
						|
    /* Check SW1 SW2    T4T 1.0 5.1.3 NOTE */
 | 
						|
    if( apduParam->statusWord == RFAL_T4T_ISO7816_STATUS_COMPLETE )
 | 
						|
    {
 | 
						|
        return ERR_NONE;
 | 
						|
    }
 | 
						|
 | 
						|
    return ERR_REQUEST;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*******************************************************************************/ 
 | 
						|
ReturnCode rfalT4TPollerComposeSelectAppl( rfalIsoDepApduBufFormat *cApduBuf, const uint8_t* aid, uint8_t aidLen, uint16_t *cApduLen )
 | 
						|
{   
 | 
						|
    rfalT4tCApduParam cAPDU;
 | 
						|
 | 
						|
    /* CLA INS P1  P2   Lc  Data   Le  */
 | 
						|
    /* 00h A4h 00h 00h  07h AID    00h */
 | 
						|
    cAPDU.CLA      = RFAL_T4T_CLA;
 | 
						|
    cAPDU.INS      = (uint8_t)RFAL_T4T_INS_SELECT;
 | 
						|
    cAPDU.P1       = RFAL_T4T_ISO7816_P1_SELECT_BY_DF_NAME;
 | 
						|
    cAPDU.P2       = RFAL_T4T_ISO7816_P2_SELECT_FIRST_OR_ONLY_OCCURENCE | RFAL_T4T_ISO7816_P2_SELECT_RETURN_FCI_TEMPLATE;
 | 
						|
    cAPDU.Lc       = aidLen;
 | 
						|
    cAPDU.Le       = 0x00;
 | 
						|
    cAPDU.LcFlag   = true;
 | 
						|
    cAPDU.LeFlag   = true;
 | 
						|
    cAPDU.cApduBuf = cApduBuf;
 | 
						|
    cAPDU.cApduLen = cApduLen;
 | 
						|
    
 | 
						|
    if( aidLen > 0U )
 | 
						|
    {
 | 
						|
        ST_MEMCPY( cAPDU.cApduBuf->apdu, aid, aidLen );
 | 
						|
    }
 | 
						|
    
 | 
						|
    return rfalT4TPollerComposeCAPDU( &cAPDU );
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*******************************************************************************/ 
 | 
						|
ReturnCode rfalT4TPollerComposeSelectFile( rfalIsoDepApduBufFormat *cApduBuf, const uint8_t* fid, uint8_t fidLen, uint16_t *cApduLen )
 | 
						|
{   
 | 
						|
    rfalT4tCApduParam cAPDU;
 | 
						|
 | 
						|
    /* CLA INS P1  P2   Lc  Data   Le  */
 | 
						|
    /* 00h A4h 00h 0Ch  02h FID    -   */    
 | 
						|
    cAPDU.CLA      = RFAL_T4T_CLA;
 | 
						|
    cAPDU.INS      = (uint8_t)RFAL_T4T_INS_SELECT;
 | 
						|
    cAPDU.P1       = RFAL_T4T_ISO7816_P1_SELECT_BY_FILEID;
 | 
						|
    cAPDU.P2       = RFAL_T4T_ISO7816_P2_SELECT_FIRST_OR_ONLY_OCCURENCE | RFAL_T4T_ISO7816_P2_SELECT_NO_RESPONSE_DATA;
 | 
						|
    cAPDU.Lc       = fidLen;
 | 
						|
    cAPDU.Le       = 0x00;
 | 
						|
    cAPDU.LcFlag   = true;
 | 
						|
    cAPDU.LeFlag   = false;
 | 
						|
    cAPDU.cApduBuf = cApduBuf;
 | 
						|
    cAPDU.cApduLen = cApduLen;
 | 
						|
    
 | 
						|
    if( fidLen > 0U )
 | 
						|
    {
 | 
						|
        ST_MEMCPY( cAPDU.cApduBuf->apdu, fid, fidLen );
 | 
						|
    }
 | 
						|
    
 | 
						|
    return rfalT4TPollerComposeCAPDU( &cAPDU );
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*******************************************************************************/ 
 | 
						|
ReturnCode rfalT4TPollerComposeSelectFileV1Mapping( rfalIsoDepApduBufFormat *cApduBuf, const uint8_t* fid, uint8_t fidLen, uint16_t *cApduLen )
 | 
						|
{   
 | 
						|
    rfalT4tCApduParam cAPDU;
 | 
						|
    
 | 
						|
    /* CLA INS P1  P2   Lc  Data   Le  */
 | 
						|
    /* 00h A4h 00h 00h  02h FID    -   */      
 | 
						|
    cAPDU.CLA      = RFAL_T4T_CLA;
 | 
						|
    cAPDU.INS      = (uint8_t)RFAL_T4T_INS_SELECT;
 | 
						|
    cAPDU.P1       = RFAL_T4T_ISO7816_P1_SELECT_BY_FILEID;
 | 
						|
    cAPDU.P2       = RFAL_T4T_ISO7816_P2_SELECT_FIRST_OR_ONLY_OCCURENCE | RFAL_T4T_ISO7816_P2_SELECT_RETURN_FCI_TEMPLATE;
 | 
						|
    cAPDU.Lc       = fidLen;
 | 
						|
    cAPDU.Le       = 0x00;
 | 
						|
    cAPDU.LcFlag   = true;
 | 
						|
    cAPDU.LeFlag   = false;
 | 
						|
    cAPDU.cApduBuf = cApduBuf;
 | 
						|
    cAPDU.cApduLen = cApduLen;
 | 
						|
    
 | 
						|
    if( fidLen > 0U )
 | 
						|
    {
 | 
						|
        ST_MEMCPY( cAPDU.cApduBuf->apdu, fid, fidLen );
 | 
						|
    }
 | 
						|
    
 | 
						|
    return rfalT4TPollerComposeCAPDU( &cAPDU );
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*******************************************************************************/ 
 | 
						|
ReturnCode rfalT4TPollerComposeReadData( rfalIsoDepApduBufFormat *cApduBuf, uint16_t offset, uint8_t expLen, uint16_t *cApduLen )
 | 
						|
{    
 | 
						|
    rfalT4tCApduParam cAPDU;
 | 
						|
  
 | 
						|
    /* CLA INS P1  P2   Lc  Data   Le  */
 | 
						|
    /* 00h B0h [Offset] -   -      len */     
 | 
						|
    cAPDU.CLA      = RFAL_T4T_CLA;
 | 
						|
    cAPDU.INS      = (uint8_t)RFAL_T4T_INS_READBINARY;
 | 
						|
    cAPDU.P1       = (uint8_t)((offset >> 8U) & 0xFFU);
 | 
						|
    cAPDU.P2       = (uint8_t)((offset >> 0U) & 0xFFU);
 | 
						|
    cAPDU.Le       = expLen;
 | 
						|
    cAPDU.LcFlag   = false;
 | 
						|
    cAPDU.LeFlag   = true;
 | 
						|
    cAPDU.cApduBuf = cApduBuf;
 | 
						|
    cAPDU.cApduLen = cApduLen;
 | 
						|
    
 | 
						|
    return rfalT4TPollerComposeCAPDU( &cAPDU );
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*******************************************************************************/ 
 | 
						|
ReturnCode rfalT4TPollerComposeReadDataODO( rfalIsoDepApduBufFormat *cApduBuf, uint32_t offset, uint8_t expLen, uint16_t *cApduLen )
 | 
						|
{    
 | 
						|
    rfalT4tCApduParam cAPDU;
 | 
						|
    uint8_t           dataIt;
 | 
						|
 | 
						|
    /* CLA INS P1  P2  Lc  Data         Le */
 | 
						|
    /* 00h B1h 00h 00h Lc  54 03 xxyyzz len */
 | 
						|
    /*                          [Offset]    */    
 | 
						|
    cAPDU.CLA      = RFAL_T4T_CLA;
 | 
						|
    cAPDU.INS      = (uint8_t)RFAL_T4T_INS_READBINARY_ODO;
 | 
						|
    cAPDU.P1       = 0x00U;
 | 
						|
    cAPDU.P2       = 0x00U;
 | 
						|
    cAPDU.Le       = expLen;
 | 
						|
    cAPDU.LcFlag   = true;
 | 
						|
    cAPDU.LeFlag   = true;
 | 
						|
    cAPDU.cApduBuf = cApduBuf;
 | 
						|
    cAPDU.cApduLen = cApduLen;
 | 
						|
    
 | 
						|
    dataIt = 0U;
 | 
						|
    cApduBuf->apdu[dataIt++] = RFAL_T4T_OFFSET_DO;
 | 
						|
    cApduBuf->apdu[dataIt++] = RFAL_T4T_LENGTH_DO;
 | 
						|
    cApduBuf->apdu[dataIt++] = (uint8_t)(offset >> 16U);
 | 
						|
    cApduBuf->apdu[dataIt++] = (uint8_t)(offset >> 8U);
 | 
						|
    cApduBuf->apdu[dataIt++] = (uint8_t)(offset);
 | 
						|
    cAPDU.Lc                 = dataIt;
 | 
						|
    
 | 
						|
    return rfalT4TPollerComposeCAPDU( &cAPDU );
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*******************************************************************************/ 
 | 
						|
ReturnCode rfalT4TPollerComposeWriteData( rfalIsoDepApduBufFormat *cApduBuf, uint16_t offset, const uint8_t* data, uint8_t dataLen, uint16_t *cApduLen )
 | 
						|
{    
 | 
						|
    rfalT4tCApduParam cAPDU;
 | 
						|
 | 
						|
 | 
						|
    /* CLA INS P1  P2   Lc  Data   Le  */
 | 
						|
    /* 00h D6h [Offset] len Data   -   */         
 | 
						|
    cAPDU.CLA      = RFAL_T4T_CLA;
 | 
						|
    cAPDU.INS      = (uint8_t)RFAL_T4T_INS_UPDATEBINARY;
 | 
						|
    cAPDU.P1       = (uint8_t)((offset >> 8U) & 0xFFU);
 | 
						|
    cAPDU.P2       = (uint8_t)((offset >> 0U) & 0xFFU);
 | 
						|
    cAPDU.Lc       = dataLen;
 | 
						|
    cAPDU.LcFlag   = true;
 | 
						|
    cAPDU.LeFlag   = false;
 | 
						|
    cAPDU.cApduBuf = cApduBuf;
 | 
						|
    cAPDU.cApduLen = cApduLen;
 | 
						|
    
 | 
						|
    if( dataLen > 0U )
 | 
						|
    {
 | 
						|
        ST_MEMCPY( cAPDU.cApduBuf->apdu, data, dataLen );
 | 
						|
    }
 | 
						|
    
 | 
						|
    return rfalT4TPollerComposeCAPDU( &cAPDU );
 | 
						|
}
 | 
						|
 | 
						|
/*******************************************************************************/ 
 | 
						|
ReturnCode rfalT4TPollerComposeWriteDataODO( rfalIsoDepApduBufFormat *cApduBuf, uint32_t offset, const uint8_t* data, uint8_t dataLen, uint16_t *cApduLen )
 | 
						|
{    
 | 
						|
    rfalT4tCApduParam cAPDU;
 | 
						|
    uint8_t           dataIt;
 | 
						|
        
 | 
						|
    /* CLA INS P1  P2   Lc  Data                     Le  */
 | 
						|
    /* 00h D7h 00h 00h  len 54 03 xxyyzz 53 Ld data  -   */
 | 
						|
    /*                           [offset]     [data]     */
 | 
						|
    cAPDU.CLA      = RFAL_T4T_CLA;
 | 
						|
    cAPDU.INS      = (uint8_t)RFAL_T4T_INS_UPDATEBINARY_ODO;
 | 
						|
    cAPDU.P1       = 0x00U;
 | 
						|
    cAPDU.P2       = 0x00U;
 | 
						|
    cAPDU.LcFlag   = true;
 | 
						|
    cAPDU.LeFlag   = false;
 | 
						|
    cAPDU.cApduBuf = cApduBuf;
 | 
						|
    cAPDU.cApduLen = cApduLen;
 | 
						|
        
 | 
						|
    dataIt = 0U;
 | 
						|
    cApduBuf->apdu[dataIt++] = RFAL_T4T_OFFSET_DO;
 | 
						|
    cApduBuf->apdu[dataIt++] = RFAL_T4T_LENGTH_DO;
 | 
						|
    cApduBuf->apdu[dataIt++] = (uint8_t)(offset >> 16U);
 | 
						|
    cApduBuf->apdu[dataIt++] = (uint8_t)(offset >> 8U);
 | 
						|
    cApduBuf->apdu[dataIt++] = (uint8_t)(offset);
 | 
						|
    cApduBuf->apdu[dataIt++] = RFAL_T4T_DATA_DO;
 | 
						|
    cApduBuf->apdu[dataIt++] = dataLen;
 | 
						|
    
 | 
						|
    if( (((uint32_t)dataLen + (uint32_t)dataIt) >= RFAL_T4T_MAX_LC) ||  (((uint32_t)dataLen + (uint32_t)dataIt) >= RFAL_FEATURE_ISO_DEP_APDU_MAX_LEN) )
 | 
						|
    {
 | 
						|
        return (ERR_NOMEM);
 | 
						|
    }
 | 
						|
    
 | 
						|
    if( dataLen > 0U )
 | 
						|
    {
 | 
						|
        ST_MEMCPY( &cAPDU.cApduBuf->apdu[dataIt], data, dataLen );
 | 
						|
    }
 | 
						|
    dataIt += dataLen;
 | 
						|
    cAPDU.Lc = dataIt;
 | 
						|
    
 | 
						|
    return rfalT4TPollerComposeCAPDU( &cAPDU );
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#endif /* RFAL_FEATURE_T4T */
 |