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