blob: 080428138f4bdb5c7574050c9cfe326aad778489 [file] [log] [blame] [edit]
/******************************************************************************
*
* Copyright 2020, 2022-2023 NXP
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
#define LOG_TAG "weaver-parser-impl"
#include <weaver_parser-impl.h>
#include <weaver_utils.h>
WeaverParserImpl *WeaverParserImpl::s_instance = NULL;
std::once_flag WeaverParserImpl::s_instanceFlag;
/* byte info for GP header of weaver commands */
#define CLA 0x80
#define INS_GET_SLOT 0x02
#define INS_READ 0x06
#define INS_WRITE 0x04
#define P1 0x00
#define P2 0x00
#define LE 0x00
/* Error code for weaver commands response */
#define SUCCESS_SW1 0x90
#define SUCCESS_SW2 0x00
#define INVALID_SLOT_SW1 0x6A
#define INVALID_SLOT_SW2 0x88
#define INVALID_P1P2_SW1 0x6A
#define INVALID_P1P2_SW2 0x86
#define INVALID_LENGTH_SW1 0x67
#define INVALID_LENGTH_SW2 0x00
/* Supported Size by Applet */
#define KEY_SIZE 16
#define VALUE_SIZE 16
#define RES_STATUS_SIZE 2
/* For Applet Read Response TAG */
#define INCORRECT_KEY_TAG 0x7F
#define THROTTING_ENABLED_TAG 0x76
#define READ_SUCCESS_TAG 0x00
#define READ_ERR_CODE_INDEX 0 // Start index of above tag in read response
#define READ_ERR_CODE_SIZE 1 // Size of above tag in read response
#define SLOT_ID_INDEX 0 // Index of slotId in getSlot response
/* For bit shifting mask */
#define SHIFT_MASK 0xff
#define BYTE3_MSB_POS 8
#define BYTE2_MSB_POS 16
#define BYTE1_MSB_POS 24
/* byte info for GP header of weaver get data command */
#define INS_GET_DATA 0xCA
/* Applet ID to be used for Weaver */
const std::vector<std::vector<uint8_t>> kWeaverAIDs = {
{0xA0, 0x00, 0x00, 0x03, 0x96, 0x10, 0x10}, // Primary AID
{0xA0, 0x00, 0x00, 0x03, 0x96, 0x54, 0x53, 0x00, 0x00, 0x00, 0x01, 0x00,
0x23, 0x00, 0x00, 0x00}, // Alternate AID
};
/**
* \brief static function to get the singleton instance of WeaverParserImpl
* class
*
* \retval instance of WeaverParserImpl.
*/
WeaverParserImpl *WeaverParserImpl::getInstance() {
/* call_once c++11 api which executes the passed function ptr exactly once,
* even if called concurrently, from several threads
*/
std::call_once(s_instanceFlag, &WeaverParserImpl::createInstance);
return s_instance;
}
/* Private function to create the instance of self class
* Same will be used for std::call_once
*/
void WeaverParserImpl::createInstance() {
LOG_D(TAG, "Entry");
s_instance = new WeaverParserImpl;
LOG_D(TAG, "Exit");
}
/**
* \brief Function to Frame weaver applet request command for open
*
* \param[out] request - framed open command as vector
*
* \retval This function return true in case of success
* In case of failure returns false.
*/
bool WeaverParserImpl::FrameOpenCmd(std::vector<uint8_t> &request) {
LOG_D(TAG, "Entry");
UNUSED(request);
LOG_D(TAG, "Exit");
return true;
}
/**
* \brief Function to Frame weaver applet request command for getSlots
*
* \param[out] request - framed getslots command as vector
*
* \retval This function return true in case of success
* In case of failure returns false.
*/
bool WeaverParserImpl::FrameGetSlotCmd(std::vector<uint8_t> &request) {
LOG_D(TAG, "Entry");
request.clear();
request.push_back(CLA);
request.push_back(INS_GET_SLOT);
request.push_back(P1);
request.push_back(P2);
request.push_back(LE);
LOG_D(TAG, "Exit");
return true;
}
/**
* \brief Function to Frame weaver applet request command for read
*
* \param[in] slotId - input slotId to be used in read request.
* \param[in] key - input key to be used in read request.
* \param[out] request - framed read command as vector
*
* \retval This function return true in case of success
* In case of failure returns false.
*/
bool WeaverParserImpl::FrameReadCmd(uint32_t slotId,
const std::vector<uint8_t> &key,
std::vector<uint8_t> &request) {
LOG_D(TAG, "Entry");
request.clear();
request.push_back(CLA);
request.push_back(INS_READ);
request.push_back(P1);
request.push_back(P2);
request.push_back(sizeof(uint32_t) + key.size()); // LC
/* convert and insert 4 Byte integer slot id as byte by byte to vector */
request.push_back(SHIFT_MASK & (slotId >> BYTE1_MSB_POS));
request.push_back(SHIFT_MASK & (slotId >> BYTE2_MSB_POS));
request.push_back(SHIFT_MASK & (slotId >> BYTE3_MSB_POS));
request.push_back(SHIFT_MASK & slotId);
request.insert(std::end(request), std::begin(key), std::end(key));
request.push_back(LE);
LOG_D(TAG, "Exit");
return true;
}
/**
* \brief Function to Frame weaver applet request command for write
*
* \param[in] slotId - input slotId to be used in write request.
* \param[in] key - input key to be used in write request.
* \param[in] value - input value to be used in write request.
* \param[out] request - framed write command as vector
*
* \retval This function return true in case of success
* In case of failure returns false.
*/
bool WeaverParserImpl::FrameWriteCmd(uint32_t slotId,
const std::vector<uint8_t> &key,
const std::vector<uint8_t> &value,
std::vector<uint8_t> &request) {
LOG_D(TAG, "Entry");
request.clear();
request.push_back(CLA);
request.push_back(INS_WRITE);
request.push_back(P1);
request.push_back(P2);
request.push_back(sizeof(uint32_t) + key.size() + value.size()); // LC
/* convert and insert 4 Byte integer slot id as byte by byte to vector */
request.push_back(SHIFT_MASK & (slotId >> BYTE1_MSB_POS));
request.push_back(SHIFT_MASK & (slotId >> BYTE2_MSB_POS));
request.push_back(SHIFT_MASK & (slotId >> BYTE3_MSB_POS));
request.push_back(SHIFT_MASK & slotId);
request.insert(std::end(request), std::begin(key), std::end(key));
request.insert(std::end(request), std::begin(value), std::end(value));
request.push_back(LE);
LOG_D(TAG, "Exit");
return true;
}
/**
* \brief Function to Frame weaver applet request command for get data
*
* \param[in] p1 - p1 value for get Data command.
* \param[in] p2 - p2 value for get Data command.
* \param[out] request - framed get data command as vector
*
* \retval This function return true in case of success
* In case of failure returns false.
*/
bool WeaverParserImpl::FrameGetDataCmd(uint8_t p1, uint8_t p2,
std::vector<uint8_t> &request) {
LOG_D(TAG, "Entry");
request.clear();
request.push_back(CLA);
request.push_back(INS_GET_DATA);
request.push_back(p1);
request.push_back(p2);
request.push_back(LE);
LOG_D(TAG, "Exit");
return true;
}
/**
* \brief Function to Parse getSlots response
*
* \param[in] response - response from applet.
* \param[out] slotInfo - parsed slots Information read out from applet
* response.
*
* \retval This function return true in case of success
* In case of failure returns false.
*/
Status_Weaver WeaverParserImpl::ParseSlotInfo(std::vector<uint8_t> response,
SlotInfo &slotInfo) {
LOG_D(TAG, "Entry");
Status_Weaver status = WEAVER_STATUS_FAILED;
slotInfo.slots = 0;
if (isSuccess(response)) {
/* Read 2 bytes for number of slot as integer. Since Applet supports no of
* slot as short*/
uint32_t slots = response.at(SLOT_ID_INDEX) << BYTE3_MSB_POS;
slots |= response.at(SLOT_ID_INDEX + 1);
slotInfo.slots = slots;
slotInfo.keySize = KEY_SIZE;
slotInfo.valueSize = VALUE_SIZE;
status = WEAVER_STATUS_OK;
}
LOG_D(TAG, "Exit");
return status;
}
/**
* \brief Function to Parse read response
*
* \param[in] response - response from applet.
* \param[out] readInfo - parsed read Information read out from applet
* response.
*
* \retval This function return true in case of success
* In case of failure returns false.
*/
Status_Weaver WeaverParserImpl::ParseReadInfo(std::vector<uint8_t> response,
ReadRespInfo &readInfo) {
LOG_D(TAG, "Entry");
Status_Weaver status = WEAVER_STATUS_FAILED;
if (response.size() < RES_STATUS_SIZE) {
LOG_E(TAG, "Exit Invalid Response Size");
return status;
}
if (isSuccess(response)) {
readInfo.timeout = 0; // Applet not supporting timeout value in read response
switch (response.at(READ_ERR_CODE_INDEX)) {
case INCORRECT_KEY_TAG:
LOG_E(TAG, "INCORRECT_KEY");
status = WEAVER_STATUS_INCORRECT_KEY;
readInfo.value.resize(0);
break;
case THROTTING_ENABLED_TAG:
LOG_E(TAG, "THROTTING_ENABLED");
status = WEAVER_STATUS_THROTTLE;
readInfo.value.resize(0);
break;
case READ_SUCCESS_TAG:
if ((VALUE_SIZE + READ_ERR_CODE_SIZE + RES_STATUS_SIZE) ==
response.size()) {
LOG_D(TAG, "SUCCESS");
readInfo.value.clear();
readInfo.value.insert(std::end(readInfo.value),
std::begin(response) + READ_ERR_CODE_SIZE,
std::end(response) - RES_STATUS_SIZE);
status = WEAVER_STATUS_OK;
} else {
LOG_E(TAG, "Invalid Response");
}
break;
default:
LOG_E(TAG, "Unknown Tag for Read Response");
}
}
LOG_D(TAG, "Exit");
return status;
}
/**
* \brief Function to Parse get data response
*
* \param[in] response - response from applet.
* \param[out] readInfo - parsed Get data Information read out from applet
* response.
*
* \retval This function return true in case of success
* In case of failure returns false.
*/
Status_Weaver WeaverParserImpl::ParseGetDataInfo(std::vector<uint8_t> response,
GetDataRespInfo &getDataInfo) {
LOG_D(TAG, "Entry");
Status_Weaver status = WEAVER_STATUS_FAILED;
int remainingLen = response.size();
if (remainingLen < RES_STATUS_SIZE) {
LOG_E(TAG, "Exit Invalid Response Size");
return status;
}
if (!isSuccess(response)) {
LOG_E(TAG, "Invalid Response code");
return status;
}
remainingLen -= RES_STATUS_SIZE;
uint8_t *readOffset = response.data();
/* remaining response should contains at least 1 byte for TAG value */
if (remainingLen < sizeof(uint8_t)) {
LOG_E(TAG, "Invalid get data response");
return status;
}
switch (*readOffset++) {
case sThrottleGetDataP1:
remainingLen--;
/* remaining response should contain at least 8 bytes of data
* where 1 byte for slot id, 1 byte for datasize, 4 bytes for timeout
* and 2 bytes for failure count */
if (remainingLen < ((2 * sizeof(uint8_t)) /* for slot id and datasize */
+ sizeof(getDataInfo.timeout) + sizeof(getDataInfo.failure_count))) {
LOG_E(TAG, "Invalid get data response");
break;
}
readOffset++; // slot id value
remainingLen--;
/* datasize value should be 6 as 4 bytes for time out + 2 bytes for failure count */
if (*readOffset++ == (sizeof(getDataInfo.timeout) +
sizeof(getDataInfo.failure_count))) {
getDataInfo.timeout = *readOffset++ << BYTE1_MSB_POS;
getDataInfo.timeout |= *readOffset++ << BYTE2_MSB_POS;
getDataInfo.timeout |= *readOffset++ << BYTE3_MSB_POS;
getDataInfo.timeout |= *readOffset++;
getDataInfo.failure_count = *readOffset++ << BYTE3_MSB_POS;
getDataInfo.failure_count |= *readOffset;
LOG_D(TAG, "THROTTLE timeout (%u) Sec, Failure Count : (%u)", getDataInfo.timeout,
getDataInfo.failure_count);
status = WEAVER_STATUS_OK;
} else {
LOG_D(TAG, "Invalid data length in GET THROTTLE DATA response");
}
break;
default:
LOG_D(TAG, "Invalid get data response TAG");
}
return status;
}
/**
* \brief Function to check if response from applet is Success or not
*
* \param[in] response - response from applet.
*
* \retval This function return true if response code from applet is success
* and false in other cases.
*/
bool WeaverParserImpl::isSuccess(std::vector<uint8_t> response) {
return (checkStatus(std::move(response)) == APP_SUCCESS) ? true : false;
}
/**
* \brief Private internal Function to check the response status code
*
* \param[in] response - response from weaver applet.
*
* \retval This function return errorcode from APP_ERR_CODE type
*/
WeaverParserImpl::APP_ERR_CODE
WeaverParserImpl::checkStatus(std::vector<uint8_t> response) {
LOG_D(TAG, "Entry");
APP_ERR_CODE status = APP_FAILED;
if (RES_STATUS_SIZE > response.size()) {
LOG_E(TAG, "Response is too short");
status = APP_FAILED;
} else if (response.at(response.size() - 2) == SUCCESS_SW1 &&
response.at(response.size() - 1) == SUCCESS_SW2) {
LOG_D(TAG, "SUCCESS");
status = APP_SUCCESS;
} else if (response.at(response.size() - 2) == INVALID_SLOT_SW1 &&
response.at(response.size() - 1) == INVALID_SLOT_SW2) {
// Invalid Slot ID
LOG_E(TAG, "Invalid Slot");
status = APP_INVALID_SLOT;
} else if (response.at(response.size() - 2) == INVALID_P1P2_SW1 &&
response.at(response.size() - 1) == INVALID_P1P2_SW2) {
// Invalid P1/P2
LOG_E(TAG, "Invalid P1/P2");
status = APP_INVALID_P1_P2;
} else if (response.at(response.size() - 2) == INVALID_LENGTH_SW1 &&
response.at(response.size() - 1) == INVALID_LENGTH_SW2) {
// Invalid Length
LOG_E(TAG, "Invalid Length");
status = APP_INVALID_LEN;
}
LOG_D(TAG, "Exit");
return status;
}
/**
* \brief Function to get Weaver Applet ID
*
* \param[out] aid - applet id of the weaver applet.
*
* \retval This function return true in case of success
* In case of failure returns false.
*/
bool WeaverParserImpl::getAppletId(std::vector<std::vector<uint8_t>> &aid) {
LOG_D(TAG, "Entry");
bool status = false;
if (kWeaverAIDs.size() > 0) {
aid = kWeaverAIDs;
status = true;
}
LOG_D(TAG, "Exit");
return status;
}