1 /******************************************************************************
2  *
3  *  Copyright 2018-2019,2022 NXP
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *  http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  ******************************************************************************/
18 /**
19  * \addtogroup ISO7816-4_application_protocol_implementation
20  *
21  * @{ */
22 #define LOG_TAG "NxpEseHal"
23 #include <ese_logs.h>
24 #include <log/log.h>
25 #include <phNxpEse_Apdu_Api.h>
26 #include <phNxpEse_Api.h>
27 
28 static ESESTATUS phNxpEse_7816_FrameCmd(pphNxpEse_7816_cpdu_t pCmd,
29                                         uint8_t** pcmd_data, uint32_t* cmd_len);
30 
31 /******************************************************************************
32  * Function         phNxpEse_7816_Transceive
33  *
34  * Description      This function prepares C-APDU and sends to p61 and receives
35  *                  response from the p61. also it parses all required fields of
36  *                  the response PDU.
37  *
38  * Returns          On Success ESESTATUS_SUCCESS else proper error code
39  *
40  ******************************************************************************/
phNxpEse_7816_Transceive(pphNxpEse_7816_cpdu_t pCmd,pphNxpEse_7816_rpdu_t pRsp)41 ESESTATUS phNxpEse_7816_Transceive(pphNxpEse_7816_cpdu_t pCmd,
42                                    pphNxpEse_7816_rpdu_t pRsp) {
43   ESESTATUS status = ESESTATUS_FAILED;
44   NXP_LOG_ESE_D(" %s Enter \n", __FUNCTION__);
45 
46   uint32_t cmd_len = 0;
47   uint8_t* pCmd_data = NULL;
48   phNxpEse_data pCmdTrans;
49   phNxpEse_data pRspTrans;
50   phNxpEse_memset(&pCmdTrans, 0x00, sizeof(phNxpEse_data));
51   phNxpEse_memset(&pRspTrans, 0x00, sizeof(phNxpEse_data));
52 
53   if (NULL == pCmd || NULL == pRsp) {
54     NXP_LOG_ESE_E(" %s Invalid parameter \n", __FUNCTION__);
55     status = ESESTATUS_INVALID_PARAMETER;
56   } else if (pCmd->cpdu_type > 1) {
57     NXP_LOG_ESE_E(" %s Invalid cpdu type \n", __FUNCTION__);
58     status = ESESTATUS_INVALID_CPDU_TYPE;
59   } else if (0 < pCmd->le_type && NULL == pRsp->pdata) {
60     /* if response is requested, but no valid res buffer
61      * provided by application */
62     NXP_LOG_ESE_E(" %s Invalid response buffer \n", __FUNCTION__);
63     status = ESESTATUS_INVALID_BUFFER;
64   } else {
65     status = phNxpEse_7816_FrameCmd(pCmd, &pCmd_data, &cmd_len);
66     if (ESESTATUS_SUCCESS == status) {
67       pCmdTrans.len = cmd_len;
68       pCmdTrans.p_data = pCmd_data;
69       status = phNxpEse_Transceive(&pCmdTrans, &pRspTrans);
70       if (ESESTATUS_SUCCESS != status) {
71         NXP_LOG_ESE_E(" %s phNxpEse_Transceive Failed \n", __FUNCTION__);
72         if ((pRspTrans.len > 0) && (pRspTrans.p_data != NULL)) {
73           pRsp->sw2 = *(pRspTrans.p_data + (pRspTrans.len - 1));
74           pRspTrans.len--;
75           pRsp->sw1 = *(pRspTrans.p_data + (pRspTrans.len - 1));
76           pRspTrans.len--;
77           pRsp->len = pRspTrans.len;
78         }
79       } else {
80         if ((pRspTrans.len > 0) && (pRspTrans.p_data != NULL)) {
81           pRsp->sw2 = *(pRspTrans.p_data + (pRspTrans.len - 1));
82           pRspTrans.len--;
83           pRsp->sw1 = *(pRspTrans.p_data + (pRspTrans.len - 1));
84           pRspTrans.len--;
85           pRsp->len = pRspTrans.len;
86           NXP_LOG_ESE_D("pRsp->len %d", pRsp->len);
87           if (pRspTrans.len > 0 && NULL != pRsp->pdata) {
88             phNxpEse_memcpy(pRsp->pdata, pRspTrans.p_data, pRspTrans.len);
89             status = ESESTATUS_SUCCESS;
90           } else if (pRspTrans.len == 0) {
91             status = ESESTATUS_SUCCESS;
92           } else {
93             /* if application response buffer is null and data is present */
94             NXP_LOG_ESE_E("Invalid Res buffer");
95             status = ESESTATUS_FAILED;
96           }
97           NXP_LOG_ESE_D("Freeing memory pRspTrans.p_data ");
98           phNxpEse_free(pRspTrans.p_data);
99           pRspTrans.p_data = NULL;
100           pRspTrans.len = 0;
101         } else {
102           NXP_LOG_ESE_E("pRspTrans.len error = %d", pRspTrans.len);
103           status = ESESTATUS_FAILED;
104         }
105       }
106       if (pCmd_data != NULL) {
107         NXP_LOG_ESE_D("Freeing memory pCmd_data");
108         phNxpEse_free(pCmd_data);
109       }
110     }
111   }
112   NXP_LOG_ESE_D(" %s Exit status 0x%x \n", __FUNCTION__, status);
113   return status;
114 }
115 
116 /**
117  * \ingroup ISO7816-4_application_protocol_implementation
118  * \brief Frames ISO7816-4 command.
119  *                  pCmd: 7816 command structure.
120  *                  pcmd_data: command buffer pointer.
121  *
122  * \param[in]       pCmd- Structure pointer passed from
123  *application
124  * \param[in]        **pcmd_data - Hold the allocated memory buffer for
125  *command.
126  * \param[in]        *cmd_len - Hold the buffer length, update by this
127  *function
128  *
129  * \retval  ESESTATUS_SUCCESS on Success else proper error code
130  *
131  */
132 
phNxpEse_7816_FrameCmd(pphNxpEse_7816_cpdu_t pCmd,uint8_t ** pcmd_data,uint32_t * cmd_len)133 static ESESTATUS phNxpEse_7816_FrameCmd(pphNxpEse_7816_cpdu_t pCmd,
134                                         uint8_t** pcmd_data,
135                                         uint32_t* cmd_len) {
136   uint32_t cmd_total_len = MIN_HEADER_LEN; /* header is always 4 bytes */
137   uint8_t* pbuff = NULL;
138   uint32_t index = 0;
139   uint8_t lc_len = 0;
140   uint8_t le_len = 0;
141 
142   NXP_LOG_ESE_D("%s  pCmd->lc = %d, pCmd->le_type = %d", __FUNCTION__, pCmd->lc,
143                 pCmd->le_type);
144   /* calculate the total buffer length */
145   if (pCmd->lc > 0) {
146     if (pCmd->cpdu_type == 0) {
147       cmd_total_len += 1; /* 1 byte LC */
148       lc_len = 1;
149     } else {
150       cmd_total_len += 3; /* 3 byte LC */
151       lc_len = 3;
152     }
153 
154     cmd_total_len += pCmd->lc; /* add data length */
155     if (pCmd->pdata == NULL) {
156       NXP_LOG_ESE_E("%s Invalid data buffer from application ", __FUNCTION__);
157       return ESESTATUS_INVALID_BUFFER;
158     }
159   } else {
160     lc_len = 0;
161     NXP_LOG_ESE_D("%s lc (data) field is not present %d", __FUNCTION__,
162                   pCmd->lc);
163   }
164 
165   if (pCmd->le_type > 0) {
166     if (pCmd->le_type == 1) {
167       cmd_total_len += 1; /* 1 byte LE */
168       le_len = 1;
169     } else if ((pCmd->le_type == 2 || pCmd->le_type == 3)) {
170       /* extended le */
171       if ((pCmd->le_type == 3) && (lc_len == 0)) {
172         /* if data field not present, than only LE would be three bytes */
173         cmd_total_len += 3; /* 3 byte LE */
174         le_len = 3;
175       } else if ((pCmd->le_type == 2) && (lc_len != 0)) {
176         /* if data field present, LE would be two bytes */
177         cmd_total_len += 2; /* 2 byte LE */
178         le_len = 2;
179       } else {
180         NXP_LOG_ESE_E("%s wrong LE type  %d", __FUNCTION__, pCmd->le_type);
181         cmd_total_len += pCmd->le_type;
182         le_len = pCmd->le_type;
183       }
184     } else {
185       NXP_LOG_ESE_E("%s wrong cpdu_type value %d", __FUNCTION__,
186                     pCmd->cpdu_type);
187       return ESESTATUS_INVALID_CPDU_TYPE;
188     }
189   } else {
190     le_len = 0;
191     NXP_LOG_ESE_D("%s le field is not present", __FUNCTION__);
192   }
193   NXP_LOG_ESE_D("%s cmd_total_len = %d, le_len = %d, lc_len = %d", __FUNCTION__,
194                 cmd_total_len, le_len, lc_len);
195 
196   pbuff = (uint8_t*)phNxpEse_calloc(cmd_total_len, sizeof(uint8_t));
197   if (pbuff == NULL) {
198     NXP_LOG_ESE_E("%s Error allocating memory", __FUNCTION__);
199     return ESESTATUS_INSUFFICIENT_RESOURCES;
200   }
201   *cmd_len = cmd_total_len;
202   *pcmd_data = pbuff;
203   index = 0;
204 
205   *(pbuff + index) = pCmd->cla;
206   index++;
207 
208   *(pbuff + index) = pCmd->ins;
209   index++;
210 
211   *(pbuff + index) = pCmd->p1;
212   index++;
213 
214   *(pbuff + index) = pCmd->p2;
215   index++;
216 
217   /* lc_len can be 0, 1 or 3 bytes */
218   if (lc_len > 0) {
219     if (lc_len == 1) {
220       *(pbuff + index) = pCmd->lc;
221       index++;
222     } else {
223       /* extended cmd buffer*/
224       *(pbuff + index) = 0x00; /* three byte lc */
225       index++;
226       *(pbuff + index) = ((pCmd->lc & 0xFF00) >> 8);
227       index++;
228       *(pbuff + index) = (pCmd->lc & 0x00FF);
229       index++;
230     }
231     /* copy the lc bytes data */
232     phNxpEse_memcpy((pbuff + index), pCmd->pdata, pCmd->lc);
233     index += pCmd->lc;
234   }
235   /* le_len can be 0, 1, 2 or 3 bytes */
236   if (le_len > 0) {
237     if (le_len == 1) {
238       if (pCmd->le == 256) {
239         /* if le is 256 assign max value*/
240         *(pbuff + index) = 0x00;
241       } else {
242         *(pbuff + index) = (uint8_t)pCmd->le;
243       }
244       index++;
245     } else {
246       if (pCmd->le == 65536) {
247         if (le_len == 3) {
248           /* assign max value */
249           *(pbuff + index) = 0x00; /* three byte le */
250           index++;
251         }
252         *(pbuff + index) = 0x00;
253         index++;
254         *(pbuff + index) = 0x00;
255         index++;
256       } else {
257         if (le_len == 3) {
258           *(pbuff + index) = 0x00; /* three byte le */
259           index++;
260         }
261         *(pbuff + index) = ((pCmd->le & 0x0000FF00) >> 8);
262         index++;
263         *(pbuff + index) = (pCmd->le & 0x000000FF);
264         index++;
265       }
266     }
267   }
268   NXP_LOG_ESE_D("Exit %s cmd_total_len = %d, index = %d", __FUNCTION__, index,
269                 cmd_total_len);
270   return ESESTATUS_SUCCESS;
271 }
272 /** @} */
273