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