• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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