1 /******************************************************************************
2 *
3 * Copyright 2020, 2022-2023 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 #define LOG_TAG "weaver-parser-impl"
20 #include <weaver_parser-impl.h>
21 #include <weaver_utils.h>
22
23 WeaverParserImpl *WeaverParserImpl::s_instance = NULL;
24 std::once_flag WeaverParserImpl::s_instanceFlag;
25
26 /* byte info for GP header of weaver commands */
27 #define CLA 0x80
28 #define INS_GET_SLOT 0x02
29 #define INS_READ 0x06
30 #define INS_WRITE 0x04
31 #define P1 0x00
32 #define P2 0x00
33 #define LE 0x00
34
35 /* Error code for weaver commands response */
36 #define SUCCESS_SW1 0x90
37 #define SUCCESS_SW2 0x00
38 #define INVALID_SLOT_SW1 0x6A
39 #define INVALID_SLOT_SW2 0x88
40 #define INVALID_P1P2_SW1 0x6A
41 #define INVALID_P1P2_SW2 0x86
42 #define INVALID_LENGTH_SW1 0x67
43 #define INVALID_LENGTH_SW2 0x00
44
45 /* Supported Size by Applet */
46 #define KEY_SIZE 16
47 #define VALUE_SIZE 16
48 #define RES_STATUS_SIZE 2
49
50 /* For Applet Read Response TAG */
51 #define INCORRECT_KEY_TAG 0x7F
52 #define THROTTING_ENABLED_TAG 0x76
53 #define READ_SUCCESS_TAG 0x00
54 #define READ_ERR_CODE_INDEX 0 // Start index of above tag in read response
55 #define READ_ERR_CODE_SIZE 1 // Size of above tag in read response
56
57 #define SLOT_ID_INDEX 0 // Index of slotId in getSlot response
58
59 /* For bit shifting mask */
60 #define SHIFT_MASK 0xff
61 #define BYTE3_MSB_POS 8
62 #define BYTE2_MSB_POS 16
63 #define BYTE1_MSB_POS 24
64
65 /* byte info for GP header of weaver get data command */
66 #define INS_GET_DATA 0xCA
67
68 /* Applet ID to be used for Weaver */
69 const std::vector<std::vector<uint8_t>> kWeaverAIDs = {
70 {0xA0, 0x00, 0x00, 0x03, 0x96, 0x10, 0x10}, // Primary AID
71 {0xA0, 0x00, 0x00, 0x03, 0x96, 0x54, 0x53, 0x00, 0x00, 0x00, 0x01, 0x00,
72 0x23, 0x00, 0x00, 0x00}, // Alternate AID
73 {0xA0, 0x00, 0x00, 0x03, 0x96, 0x10, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
74 0x23, 0x00, 0x00, 0x00}, // Alternate AID
75 };
76
77 /**
78 * \brief static function to get the singleton instance of WeaverParserImpl
79 * class
80 *
81 * \retval instance of WeaverParserImpl.
82 */
getInstance()83 WeaverParserImpl *WeaverParserImpl::getInstance() {
84 /* call_once c++11 api which executes the passed function ptr exactly once,
85 * even if called concurrently, from several threads
86 */
87 std::call_once(s_instanceFlag, &WeaverParserImpl::createInstance);
88 return s_instance;
89 }
90
91 /* Private function to create the instance of self class
92 * Same will be used for std::call_once
93 */
createInstance()94 void WeaverParserImpl::createInstance() {
95 LOG_D(TAG, "Entry");
96 s_instance = new WeaverParserImpl;
97 LOG_D(TAG, "Exit");
98 }
99
100 /**
101 * \brief Function to Frame weaver applet request command for open
102 *
103 * \param[out] request - framed open command as vector
104 *
105 * \retval This function return true in case of success
106 * In case of failure returns false.
107 */
FrameOpenCmd(std::vector<uint8_t> & request)108 bool WeaverParserImpl::FrameOpenCmd(std::vector<uint8_t> &request) {
109 LOG_D(TAG, "Entry");
110 UNUSED(request);
111 LOG_D(TAG, "Exit");
112 return true;
113 }
114
115 /**
116 * \brief Function to Frame weaver applet request command for getSlots
117 *
118 * \param[out] request - framed getslots command as vector
119 *
120 * \retval This function return true in case of success
121 * In case of failure returns false.
122 */
FrameGetSlotCmd(std::vector<uint8_t> & request)123 bool WeaverParserImpl::FrameGetSlotCmd(std::vector<uint8_t> &request) {
124 LOG_D(TAG, "Entry");
125 request.clear();
126 request.push_back(CLA);
127 request.push_back(INS_GET_SLOT);
128 request.push_back(P1);
129 request.push_back(P2);
130 request.push_back(LE);
131 LOG_D(TAG, "Exit");
132 return true;
133 }
134
135 /**
136 * \brief Function to Frame weaver applet request command for read
137 *
138 * \param[in] slotId - input slotId to be used in read request.
139 * \param[in] key - input key to be used in read request.
140 * \param[out] request - framed read command as vector
141 *
142 * \retval This function return true in case of success
143 * In case of failure returns false.
144 */
FrameReadCmd(uint32_t slotId,const std::vector<uint8_t> & key,std::vector<uint8_t> & request)145 bool WeaverParserImpl::FrameReadCmd(uint32_t slotId,
146 const std::vector<uint8_t> &key,
147 std::vector<uint8_t> &request) {
148 LOG_D(TAG, "Entry");
149 request.clear();
150 request.push_back(CLA);
151 request.push_back(INS_READ);
152 request.push_back(P1);
153 request.push_back(P2);
154 request.push_back(sizeof(uint32_t) + key.size()); // LC
155 /* convert and insert 4 Byte integer slot id as byte by byte to vector */
156 request.push_back(SHIFT_MASK & (slotId >> BYTE1_MSB_POS));
157 request.push_back(SHIFT_MASK & (slotId >> BYTE2_MSB_POS));
158 request.push_back(SHIFT_MASK & (slotId >> BYTE3_MSB_POS));
159 request.push_back(SHIFT_MASK & slotId);
160 request.insert(std::end(request), std::begin(key), std::end(key));
161 request.push_back(LE);
162 LOG_D(TAG, "Exit");
163 return true;
164 }
165
166 /**
167 * \brief Function to Frame weaver applet request command for write
168 *
169 * \param[in] slotId - input slotId to be used in write request.
170 * \param[in] key - input key to be used in write request.
171 * \param[in] value - input value to be used in write request.
172 * \param[out] request - framed write command as vector
173 *
174 * \retval This function return true in case of success
175 * In case of failure returns false.
176 */
FrameWriteCmd(uint32_t slotId,const std::vector<uint8_t> & key,const std::vector<uint8_t> & value,std::vector<uint8_t> & request)177 bool WeaverParserImpl::FrameWriteCmd(uint32_t slotId,
178 const std::vector<uint8_t> &key,
179 const std::vector<uint8_t> &value,
180 std::vector<uint8_t> &request) {
181 LOG_D(TAG, "Entry");
182 request.clear();
183 request.push_back(CLA);
184 request.push_back(INS_WRITE);
185 request.push_back(P1);
186 request.push_back(P2);
187 request.push_back(sizeof(uint32_t) + key.size() + value.size()); // LC
188 /* convert and insert 4 Byte integer slot id as byte by byte to vector */
189 request.push_back(SHIFT_MASK & (slotId >> BYTE1_MSB_POS));
190 request.push_back(SHIFT_MASK & (slotId >> BYTE2_MSB_POS));
191 request.push_back(SHIFT_MASK & (slotId >> BYTE3_MSB_POS));
192 request.push_back(SHIFT_MASK & slotId);
193 request.insert(std::end(request), std::begin(key), std::end(key));
194 request.insert(std::end(request), std::begin(value), std::end(value));
195 request.push_back(LE);
196 LOG_D(TAG, "Exit");
197 return true;
198 }
199
200 /**
201 * \brief Function to Frame weaver applet request command for get data
202 *
203 * \param[in] p1 - p1 value for get Data command.
204 * \param[in] p2 - p2 value for get Data command.
205 * \param[out] request - framed get data command as vector
206 *
207 * \retval This function return true in case of success
208 * In case of failure returns false.
209 */
FrameGetDataCmd(uint8_t p1,uint8_t p2,std::vector<uint8_t> & request)210 bool WeaverParserImpl::FrameGetDataCmd(uint8_t p1, uint8_t p2,
211 std::vector<uint8_t> &request) {
212 LOG_D(TAG, "Entry");
213 request.clear();
214 request.push_back(CLA);
215 request.push_back(INS_GET_DATA);
216 request.push_back(p1);
217 request.push_back(p2);
218 request.push_back(LE);
219 LOG_D(TAG, "Exit");
220 return true;
221 }
222
223 /**
224 * \brief Function to Parse getSlots response
225 *
226 * \param[in] response - response from applet.
227 * \param[out] slotInfo - parsed slots Information read out from applet
228 * response.
229 *
230 * \retval This function return true in case of success
231 * In case of failure returns false.
232 */
ParseSlotInfo(std::vector<uint8_t> response,SlotInfo & slotInfo)233 Status_Weaver WeaverParserImpl::ParseSlotInfo(std::vector<uint8_t> response,
234 SlotInfo &slotInfo) {
235 LOG_D(TAG, "Entry");
236 Status_Weaver status = WEAVER_STATUS_FAILED;
237 slotInfo.slots = 0;
238 if (isSuccess(response)) {
239 /* Read 2 bytes for number of slot as integer. Since Applet supports no of
240 * slot as short*/
241 uint32_t slots = response.at(SLOT_ID_INDEX) << BYTE3_MSB_POS;
242 slots |= response.at(SLOT_ID_INDEX + 1);
243 slotInfo.slots = slots;
244 slotInfo.keySize = KEY_SIZE;
245 slotInfo.valueSize = VALUE_SIZE;
246 status = WEAVER_STATUS_OK;
247 }
248 LOG_D(TAG, "Exit");
249 return status;
250 }
251
252 /**
253 * \brief Function to Parse read response
254 *
255 * \param[in] response - response from applet.
256 * \param[out] readInfo - parsed read Information read out from applet
257 * response.
258 *
259 * \retval This function return true in case of success
260 * In case of failure returns false.
261 */
ParseReadInfo(std::vector<uint8_t> response,ReadRespInfo & readInfo)262 Status_Weaver WeaverParserImpl::ParseReadInfo(std::vector<uint8_t> response,
263 ReadRespInfo &readInfo) {
264 LOG_D(TAG, "Entry");
265 Status_Weaver status = WEAVER_STATUS_FAILED;
266 if (response.size() < RES_STATUS_SIZE) {
267 LOG_E(TAG, "Exit Invalid Response Size");
268 return status;
269 }
270 if (isSuccess(response)) {
271 readInfo.timeout = 0; // Applet not supporting timeout value in read response
272 switch (response.at(READ_ERR_CODE_INDEX)) {
273 case INCORRECT_KEY_TAG:
274 LOG_E(TAG, "INCORRECT_KEY");
275 status = WEAVER_STATUS_INCORRECT_KEY;
276 readInfo.value.resize(0);
277 break;
278 case THROTTING_ENABLED_TAG:
279 LOG_E(TAG, "THROTTING_ENABLED");
280 status = WEAVER_STATUS_THROTTLE;
281 readInfo.value.resize(0);
282 break;
283 case READ_SUCCESS_TAG:
284 if ((VALUE_SIZE + READ_ERR_CODE_SIZE + RES_STATUS_SIZE) ==
285 response.size()) {
286 LOG_D(TAG, "SUCCESS");
287 readInfo.value.clear();
288 readInfo.value.insert(std::end(readInfo.value),
289 std::begin(response) + READ_ERR_CODE_SIZE,
290 std::end(response) - RES_STATUS_SIZE);
291 status = WEAVER_STATUS_OK;
292 } else {
293 LOG_E(TAG, "Invalid Response");
294 }
295 break;
296 default:
297 LOG_E(TAG, "Unknown Tag for Read Response");
298 }
299 }
300 LOG_D(TAG, "Exit");
301 return status;
302 }
303
304 /**
305 * \brief Function to Parse get data response
306 *
307 * \param[in] response - response from applet.
308 * \param[out] readInfo - parsed Get data Information read out from applet
309 * response.
310 *
311 * \retval This function return true in case of success
312 * In case of failure returns false.
313 */
ParseGetDataInfo(std::vector<uint8_t> response,GetDataRespInfo & getDataInfo)314 Status_Weaver WeaverParserImpl::ParseGetDataInfo(std::vector<uint8_t> response,
315 GetDataRespInfo &getDataInfo) {
316 LOG_D(TAG, "Entry");
317 Status_Weaver status = WEAVER_STATUS_FAILED;
318 int remainingLen = response.size();
319 if (remainingLen < RES_STATUS_SIZE) {
320 LOG_E(TAG, "Exit Invalid Response Size");
321 return status;
322 }
323 if (!isSuccess(response)) {
324 LOG_E(TAG, "Invalid Response code");
325 return status;
326 }
327 remainingLen -= RES_STATUS_SIZE;
328 uint8_t *readOffset = response.data();
329 /* remaining response should contains at least 1 byte for TAG value */
330 if (remainingLen < sizeof(uint8_t)) {
331 LOG_E(TAG, "Invalid get data response");
332 return status;
333 }
334 switch (*readOffset++) {
335 case sThrottleGetDataP1:
336 remainingLen--;
337 /* remaining response should contain at least 8 bytes of data
338 * where 1 byte for slot id, 1 byte for datasize, 4 bytes for timeout
339 * and 2 bytes for failure count */
340 if (remainingLen < ((2 * sizeof(uint8_t)) /* for slot id and datasize */
341 + sizeof(getDataInfo.timeout) + sizeof(getDataInfo.failure_count))) {
342 LOG_E(TAG, "Invalid get data response");
343 break;
344 }
345 readOffset++; // slot id value
346 remainingLen--;
347 /* datasize value should be 6 as 4 bytes for time out + 2 bytes for failure count */
348 if (*readOffset++ == (sizeof(getDataInfo.timeout) +
349 sizeof(getDataInfo.failure_count))) {
350 getDataInfo.timeout = *readOffset++ << BYTE1_MSB_POS;
351 getDataInfo.timeout |= *readOffset++ << BYTE2_MSB_POS;
352 getDataInfo.timeout |= *readOffset++ << BYTE3_MSB_POS;
353 getDataInfo.timeout |= *readOffset++;
354 getDataInfo.failure_count = *readOffset++ << BYTE3_MSB_POS;
355 getDataInfo.failure_count |= *readOffset;
356 LOG_D(TAG, "THROTTLE timeout (%u) Sec, Failure Count : (%u)", getDataInfo.timeout,
357 getDataInfo.failure_count);
358 status = WEAVER_STATUS_OK;
359 } else {
360 LOG_D(TAG, "Invalid data length in GET THROTTLE DATA response");
361 }
362 break;
363 default:
364 LOG_D(TAG, "Invalid get data response TAG");
365 }
366 return status;
367 }
368
369 /**
370 * \brief Function to check if response from applet is Success or not
371 *
372 * \param[in] response - response from applet.
373 *
374 * \retval This function return true if response code from applet is success
375 * and false in other cases.
376 */
isSuccess(std::vector<uint8_t> response)377 bool WeaverParserImpl::isSuccess(std::vector<uint8_t> response) {
378 return (checkStatus(std::move(response)) == APP_SUCCESS) ? true : false;
379 }
380
381 /**
382 * \brief Private internal Function to check the response status code
383 *
384 * \param[in] response - response from weaver applet.
385 *
386 * \retval This function return errorcode from APP_ERR_CODE type
387 */
388 WeaverParserImpl::APP_ERR_CODE
checkStatus(std::vector<uint8_t> response)389 WeaverParserImpl::checkStatus(std::vector<uint8_t> response) {
390 LOG_D(TAG, "Entry");
391 APP_ERR_CODE status = APP_FAILED;
392 if (RES_STATUS_SIZE > response.size()) {
393 LOG_E(TAG, "Response is too short");
394 status = APP_FAILED;
395 } else if (response.at(response.size() - 2) == SUCCESS_SW1 &&
396 response.at(response.size() - 1) == SUCCESS_SW2) {
397 LOG_D(TAG, "SUCCESS");
398 status = APP_SUCCESS;
399 } else if (response.at(response.size() - 2) == INVALID_SLOT_SW1 &&
400 response.at(response.size() - 1) == INVALID_SLOT_SW2) {
401 // Invalid Slot ID
402 LOG_E(TAG, "Invalid Slot");
403 status = APP_INVALID_SLOT;
404 } else if (response.at(response.size() - 2) == INVALID_P1P2_SW1 &&
405 response.at(response.size() - 1) == INVALID_P1P2_SW2) {
406 // Invalid P1/P2
407 LOG_E(TAG, "Invalid P1/P2");
408 status = APP_INVALID_P1_P2;
409 } else if (response.at(response.size() - 2) == INVALID_LENGTH_SW1 &&
410 response.at(response.size() - 1) == INVALID_LENGTH_SW2) {
411 // Invalid Length
412 LOG_E(TAG, "Invalid Length");
413 status = APP_INVALID_LEN;
414 }
415 LOG_D(TAG, "Exit");
416 return status;
417 }
418
419 /**
420 * \brief Function to get Weaver Applet ID
421 *
422 * \param[out] aid - applet id of the weaver applet.
423 *
424 * \retval This function return true in case of success
425 * In case of failure returns false.
426 */
getAppletId(std::vector<std::vector<uint8_t>> & aid)427 bool WeaverParserImpl::getAppletId(std::vector<std::vector<uint8_t>> &aid) {
428 LOG_D(TAG, "Entry");
429 bool status = false;
430 if (kWeaverAIDs.size() > 0) {
431 aid = kWeaverAIDs;
432 status = true;
433 }
434 LOG_D(TAG, "Exit");
435 return status;
436 }
437