rfal_t4t.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. /******************************************************************************
  2. * \attention
  3. *
  4. * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
  5. *
  6. * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
  7. * You may not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at:
  9. *
  10. * www.st.com/myliberty
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
  15. * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
  17. * See the License for the specific language governing permissions and
  18. * limitations under the License.
  19. *
  20. ******************************************************************************/
  21. /*
  22. * PROJECT: ST25R391x firmware
  23. * Revision:
  24. * LANGUAGE: ISO C99
  25. */
  26. /*! \file rfal_t4t.h
  27. *
  28. * \author Gustavo Patricio
  29. *
  30. * \brief Provides convenience methods and definitions for T4T (ISO7816-4)
  31. *
  32. * This module provides an interface to exchange T4T APDUs according to
  33. * NFC Forum T4T and ISO7816-4
  34. *
  35. * This implementation was based on the following specs:
  36. * - ISO/IEC 7816-4 3rd Edition 2013-04-15
  37. * - NFC Forum T4T Technical Specification 1.0 2017-08-28
  38. *
  39. */
  40. /*
  41. ******************************************************************************
  42. * INCLUDES
  43. ******************************************************************************
  44. */
  45. #include "../include/rfal_t4t.h"
  46. #include "../utils.h"
  47. /*
  48. ******************************************************************************
  49. * ENABLE SWITCH
  50. ******************************************************************************
  51. */
  52. #ifndef RFAL_FEATURE_T4T
  53. #define RFAL_FEATURE_T4T false /* T4T module configuration missing. Disabled by default */
  54. #endif
  55. #if RFAL_FEATURE_T4T
  56. /*
  57. ******************************************************************************
  58. * GLOBAL DEFINES
  59. ******************************************************************************
  60. */
  61. #define RFAL_T4T_OFFSET_DO 0x54U /*!< Tag value for offset BER-TLV data object */
  62. #define RFAL_T4T_LENGTH_DO 0x03U /*!< Len value for offset BER-TLV data object */
  63. #define RFAL_T4T_DATA_DO 0x53U /*!< Tag value for data BER-TLV data object */
  64. #define RFAL_T4T_MAX_LC 255U /*!< Maximum Lc value for short Lc coding */
  65. /*
  66. ******************************************************************************
  67. * GLOBAL TYPES
  68. ******************************************************************************
  69. */
  70. /*
  71. ******************************************************************************
  72. * GLOBAL MACROS
  73. ******************************************************************************
  74. */
  75. /*
  76. ******************************************************************************
  77. * LOCAL VARIABLES
  78. ******************************************************************************
  79. */
  80. /*
  81. ******************************************************************************
  82. * GLOBAL FUNCTIONS
  83. ******************************************************************************
  84. */
  85. /*******************************************************************************/
  86. ReturnCode rfalT4TPollerComposeCAPDU(const rfalT4tCApduParam* apduParam) {
  87. uint8_t hdrLen;
  88. uint16_t msgIt;
  89. if((apduParam == NULL) || (apduParam->cApduBuf == NULL) || (apduParam->cApduLen == NULL)) {
  90. return ERR_PARAM;
  91. }
  92. msgIt = 0;
  93. *(apduParam->cApduLen) = 0;
  94. /*******************************************************************************/
  95. /* Compute Command-APDU according to the format T4T 1.0 5.1.2 & ISO7816-4 2013 Table 1 */
  96. /* Check if Data is present */
  97. if(apduParam->LcFlag) {
  98. if(apduParam->Lc == 0U) {
  99. /* Extended field coding not supported */
  100. return ERR_PARAM;
  101. }
  102. /* Check whether requested Lc fits */
  103. #pragma GCC diagnostic ignored "-Wtype-limits"
  104. if((uint16_t)apduParam->Lc >
  105. (uint16_t)(RFAL_FEATURE_ISO_DEP_APDU_MAX_LEN - RFAL_T4T_LE_LEN)) {
  106. return ERR_PARAM; /* PRQA S 2880 # MISRA 2.1 - Unreachable code due to configuration option being set/unset */
  107. }
  108. /* Calculate the header length a place the data/body where it should be */
  109. hdrLen = RFAL_T4T_MAX_CAPDU_PROLOGUE_LEN + RFAL_T4T_LC_LEN;
  110. /* make sure not to exceed buffer size */
  111. if(((uint16_t)hdrLen + (uint16_t)apduParam->Lc +
  112. (apduParam->LeFlag ? RFAL_T4T_LC_LEN : 0U)) > RFAL_FEATURE_ISO_DEP_APDU_MAX_LEN) {
  113. return ERR_NOMEM; /* PRQA S 2880 # MISRA 2.1 - Unreachable code due to configuration option being set/unset */
  114. }
  115. ST_MEMMOVE(&apduParam->cApduBuf->apdu[hdrLen], apduParam->cApduBuf->apdu, apduParam->Lc);
  116. }
  117. /* Prepend the ADPDU's header */
  118. apduParam->cApduBuf->apdu[msgIt++] = apduParam->CLA;
  119. apduParam->cApduBuf->apdu[msgIt++] = apduParam->INS;
  120. apduParam->cApduBuf->apdu[msgIt++] = apduParam->P1;
  121. apduParam->cApduBuf->apdu[msgIt++] = apduParam->P2;
  122. /* Check if Data field length is to be added */
  123. if(apduParam->LcFlag) {
  124. apduParam->cApduBuf->apdu[msgIt++] = apduParam->Lc;
  125. msgIt += apduParam->Lc;
  126. }
  127. /* Check if Expected Response Length is to be added */
  128. if(apduParam->LeFlag) {
  129. apduParam->cApduBuf->apdu[msgIt++] = apduParam->Le;
  130. }
  131. *(apduParam->cApduLen) = msgIt;
  132. return ERR_NONE;
  133. }
  134. /*******************************************************************************/
  135. ReturnCode rfalT4TPollerParseRAPDU(rfalT4tRApduParam* apduParam) {
  136. if((apduParam == NULL) || (apduParam->rApduBuf == NULL)) {
  137. return ERR_PARAM;
  138. }
  139. if(apduParam->rcvdLen < RFAL_T4T_MAX_RAPDU_SW1SW2_LEN) {
  140. return ERR_PROTO;
  141. }
  142. apduParam->rApduBodyLen = (apduParam->rcvdLen - (uint16_t)RFAL_T4T_MAX_RAPDU_SW1SW2_LEN);
  143. apduParam->statusWord = GETU16((&apduParam->rApduBuf->apdu[apduParam->rApduBodyLen]));
  144. /* Check SW1 SW2 T4T 1.0 5.1.3 NOTE */
  145. if(apduParam->statusWord == RFAL_T4T_ISO7816_STATUS_COMPLETE) {
  146. return ERR_NONE;
  147. }
  148. return ERR_REQUEST;
  149. }
  150. /*******************************************************************************/
  151. ReturnCode rfalT4TPollerComposeSelectAppl(
  152. rfalIsoDepApduBufFormat* cApduBuf,
  153. const uint8_t* aid,
  154. uint8_t aidLen,
  155. uint16_t* cApduLen) {
  156. rfalT4tCApduParam cAPDU;
  157. /* CLA INS P1 P2 Lc Data Le */
  158. /* 00h A4h 00h 00h 07h AID 00h */
  159. cAPDU.CLA = RFAL_T4T_CLA;
  160. cAPDU.INS = (uint8_t)RFAL_T4T_INS_SELECT;
  161. cAPDU.P1 = RFAL_T4T_ISO7816_P1_SELECT_BY_DF_NAME;
  162. cAPDU.P2 = RFAL_T4T_ISO7816_P2_SELECT_FIRST_OR_ONLY_OCCURENCE |
  163. RFAL_T4T_ISO7816_P2_SELECT_RETURN_FCI_TEMPLATE;
  164. cAPDU.Lc = aidLen;
  165. cAPDU.Le = 0x00;
  166. cAPDU.LcFlag = true;
  167. cAPDU.LeFlag = true;
  168. cAPDU.cApduBuf = cApduBuf;
  169. cAPDU.cApduLen = cApduLen;
  170. if(aidLen > 0U) {
  171. ST_MEMCPY(cAPDU.cApduBuf->apdu, aid, aidLen);
  172. }
  173. return rfalT4TPollerComposeCAPDU(&cAPDU);
  174. }
  175. /*******************************************************************************/
  176. ReturnCode rfalT4TPollerComposeSelectFile(
  177. rfalIsoDepApduBufFormat* cApduBuf,
  178. const uint8_t* fid,
  179. uint8_t fidLen,
  180. uint16_t* cApduLen) {
  181. rfalT4tCApduParam cAPDU;
  182. /* CLA INS P1 P2 Lc Data Le */
  183. /* 00h A4h 00h 0Ch 02h FID - */
  184. cAPDU.CLA = RFAL_T4T_CLA;
  185. cAPDU.INS = (uint8_t)RFAL_T4T_INS_SELECT;
  186. cAPDU.P1 = RFAL_T4T_ISO7816_P1_SELECT_BY_FILEID;
  187. cAPDU.P2 = RFAL_T4T_ISO7816_P2_SELECT_FIRST_OR_ONLY_OCCURENCE |
  188. RFAL_T4T_ISO7816_P2_SELECT_NO_RESPONSE_DATA;
  189. cAPDU.Lc = fidLen;
  190. cAPDU.Le = 0x00;
  191. cAPDU.LcFlag = true;
  192. cAPDU.LeFlag = false;
  193. cAPDU.cApduBuf = cApduBuf;
  194. cAPDU.cApduLen = cApduLen;
  195. if(fidLen > 0U) {
  196. ST_MEMCPY(cAPDU.cApduBuf->apdu, fid, fidLen);
  197. }
  198. return rfalT4TPollerComposeCAPDU(&cAPDU);
  199. }
  200. /*******************************************************************************/
  201. ReturnCode rfalT4TPollerComposeSelectFileV1Mapping(
  202. rfalIsoDepApduBufFormat* cApduBuf,
  203. const uint8_t* fid,
  204. uint8_t fidLen,
  205. uint16_t* cApduLen) {
  206. rfalT4tCApduParam cAPDU;
  207. /* CLA INS P1 P2 Lc Data Le */
  208. /* 00h A4h 00h 00h 02h FID - */
  209. cAPDU.CLA = RFAL_T4T_CLA;
  210. cAPDU.INS = (uint8_t)RFAL_T4T_INS_SELECT;
  211. cAPDU.P1 = RFAL_T4T_ISO7816_P1_SELECT_BY_FILEID;
  212. cAPDU.P2 = RFAL_T4T_ISO7816_P2_SELECT_FIRST_OR_ONLY_OCCURENCE |
  213. RFAL_T4T_ISO7816_P2_SELECT_RETURN_FCI_TEMPLATE;
  214. cAPDU.Lc = fidLen;
  215. cAPDU.Le = 0x00;
  216. cAPDU.LcFlag = true;
  217. cAPDU.LeFlag = false;
  218. cAPDU.cApduBuf = cApduBuf;
  219. cAPDU.cApduLen = cApduLen;
  220. if(fidLen > 0U) {
  221. ST_MEMCPY(cAPDU.cApduBuf->apdu, fid, fidLen);
  222. }
  223. return rfalT4TPollerComposeCAPDU(&cAPDU);
  224. }
  225. /*******************************************************************************/
  226. ReturnCode rfalT4TPollerComposeReadData(
  227. rfalIsoDepApduBufFormat* cApduBuf,
  228. uint16_t offset,
  229. uint8_t expLen,
  230. uint16_t* cApduLen) {
  231. rfalT4tCApduParam cAPDU;
  232. /* CLA INS P1 P2 Lc Data Le */
  233. /* 00h B0h [Offset] - - len */
  234. cAPDU.CLA = RFAL_T4T_CLA;
  235. cAPDU.INS = (uint8_t)RFAL_T4T_INS_READBINARY;
  236. cAPDU.P1 = (uint8_t)((offset >> 8U) & 0xFFU);
  237. cAPDU.P2 = (uint8_t)((offset >> 0U) & 0xFFU);
  238. cAPDU.Le = expLen;
  239. cAPDU.LcFlag = false;
  240. cAPDU.LeFlag = true;
  241. cAPDU.cApduBuf = cApduBuf;
  242. cAPDU.cApduLen = cApduLen;
  243. return rfalT4TPollerComposeCAPDU(&cAPDU);
  244. }
  245. /*******************************************************************************/
  246. ReturnCode rfalT4TPollerComposeReadDataODO(
  247. rfalIsoDepApduBufFormat* cApduBuf,
  248. uint32_t offset,
  249. uint8_t expLen,
  250. uint16_t* cApduLen) {
  251. rfalT4tCApduParam cAPDU;
  252. uint8_t dataIt;
  253. /* CLA INS P1 P2 Lc Data Le */
  254. /* 00h B1h 00h 00h Lc 54 03 xxyyzz len */
  255. /* [Offset] */
  256. cAPDU.CLA = RFAL_T4T_CLA;
  257. cAPDU.INS = (uint8_t)RFAL_T4T_INS_READBINARY_ODO;
  258. cAPDU.P1 = 0x00U;
  259. cAPDU.P2 = 0x00U;
  260. cAPDU.Le = expLen;
  261. cAPDU.LcFlag = true;
  262. cAPDU.LeFlag = true;
  263. cAPDU.cApduBuf = cApduBuf;
  264. cAPDU.cApduLen = cApduLen;
  265. dataIt = 0U;
  266. cApduBuf->apdu[dataIt++] = RFAL_T4T_OFFSET_DO;
  267. cApduBuf->apdu[dataIt++] = RFAL_T4T_LENGTH_DO;
  268. cApduBuf->apdu[dataIt++] = (uint8_t)(offset >> 16U);
  269. cApduBuf->apdu[dataIt++] = (uint8_t)(offset >> 8U);
  270. cApduBuf->apdu[dataIt++] = (uint8_t)(offset);
  271. cAPDU.Lc = dataIt;
  272. return rfalT4TPollerComposeCAPDU(&cAPDU);
  273. }
  274. /*******************************************************************************/
  275. ReturnCode rfalT4TPollerComposeWriteData(
  276. rfalIsoDepApduBufFormat* cApduBuf,
  277. uint16_t offset,
  278. const uint8_t* data,
  279. uint8_t dataLen,
  280. uint16_t* cApduLen) {
  281. rfalT4tCApduParam cAPDU;
  282. /* CLA INS P1 P2 Lc Data Le */
  283. /* 00h D6h [Offset] len Data - */
  284. cAPDU.CLA = RFAL_T4T_CLA;
  285. cAPDU.INS = (uint8_t)RFAL_T4T_INS_UPDATEBINARY;
  286. cAPDU.P1 = (uint8_t)((offset >> 8U) & 0xFFU);
  287. cAPDU.P2 = (uint8_t)((offset >> 0U) & 0xFFU);
  288. cAPDU.Lc = dataLen;
  289. cAPDU.LcFlag = true;
  290. cAPDU.LeFlag = false;
  291. cAPDU.cApduBuf = cApduBuf;
  292. cAPDU.cApduLen = cApduLen;
  293. if(dataLen > 0U) {
  294. ST_MEMCPY(cAPDU.cApduBuf->apdu, data, dataLen);
  295. }
  296. return rfalT4TPollerComposeCAPDU(&cAPDU);
  297. }
  298. /*******************************************************************************/
  299. ReturnCode rfalT4TPollerComposeWriteDataODO(
  300. rfalIsoDepApduBufFormat* cApduBuf,
  301. uint32_t offset,
  302. const uint8_t* data,
  303. uint8_t dataLen,
  304. uint16_t* cApduLen) {
  305. rfalT4tCApduParam cAPDU;
  306. uint8_t dataIt;
  307. /* CLA INS P1 P2 Lc Data Le */
  308. /* 00h D7h 00h 00h len 54 03 xxyyzz 53 Ld data - */
  309. /* [offset] [data] */
  310. cAPDU.CLA = RFAL_T4T_CLA;
  311. cAPDU.INS = (uint8_t)RFAL_T4T_INS_UPDATEBINARY_ODO;
  312. cAPDU.P1 = 0x00U;
  313. cAPDU.P2 = 0x00U;
  314. cAPDU.LcFlag = true;
  315. cAPDU.LeFlag = false;
  316. cAPDU.cApduBuf = cApduBuf;
  317. cAPDU.cApduLen = cApduLen;
  318. dataIt = 0U;
  319. cApduBuf->apdu[dataIt++] = RFAL_T4T_OFFSET_DO;
  320. cApduBuf->apdu[dataIt++] = RFAL_T4T_LENGTH_DO;
  321. cApduBuf->apdu[dataIt++] = (uint8_t)(offset >> 16U);
  322. cApduBuf->apdu[dataIt++] = (uint8_t)(offset >> 8U);
  323. cApduBuf->apdu[dataIt++] = (uint8_t)(offset);
  324. cApduBuf->apdu[dataIt++] = RFAL_T4T_DATA_DO;
  325. cApduBuf->apdu[dataIt++] = dataLen;
  326. if((((uint32_t)dataLen + (uint32_t)dataIt) >= RFAL_T4T_MAX_LC) ||
  327. (((uint32_t)dataLen + (uint32_t)dataIt) >= RFAL_FEATURE_ISO_DEP_APDU_MAX_LEN)) {
  328. return (ERR_NOMEM);
  329. }
  330. if(dataLen > 0U) {
  331. ST_MEMCPY(&cAPDU.cApduBuf->apdu[dataIt], data, dataLen);
  332. }
  333. dataIt += dataLen;
  334. cAPDU.Lc = dataIt;
  335. return rfalT4TPollerComposeCAPDU(&cAPDU);
  336. }
  337. #endif /* RFAL_FEATURE_T4T */