C++程序  |  1948行  |  68.74 KB

/*******************************************************************************
 *
 *  Copyright 2018 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 "LSClient"
#include <LsClient.h>
#include <LsLib.h>
#include <errno.h>
#include <log/log.h>
#include <stdlib.h>
#include <string.h>

extern bool ese_debug_enabled;

static int32_t gsTransceiveTimeout = 120000;
static uint8_t gsCmd_Buffer[64 * 1024];
static int32_t gsCmd_count = 0;
static bool gsIslastcmdLoad;
static bool gsSendBack_cmds = false;
static uint8_t* gspBuffer;
static uint8_t gsStoreData[22];
static uint8_t gsTag42Arr[17];
static uint8_t gsTag45Arr[9];
static uint8_t gsLsExecuteResp[4];
static int32_t gsResp_len = 0;

LSCSTATUS(*Applet_load_seqhandler[])
(Lsc_ImageInfo_t* pContext, LSCSTATUS status, Lsc_TranscieveInfo_t* pInfo) = {
    LSC_OpenChannel, LSC_SelectLsc, LSC_StoreData, LSC_loadapplet, NULL};

/*******************************************************************************
**
** Function:        Perform_LSC
**
** Description:     Performs the LSC download sequence
**
** Returns:         Success if ok.
**
*******************************************************************************/
LSCSTATUS Perform_LSC(const char* name, const char* dest, const uint8_t* pdata,
                      uint16_t len, uint8_t* respSW) {
  static const char fn[] = "Perform_LSC";
  ALOGD_IF(ese_debug_enabled, "%s: enter; sha-len=%d", fn, len);
  if ((pdata == NULL) || (len == 0x00)) {
    ALOGE("%s: Invalid SHA-data", fn);
    return LSCSTATUS_FAILED;
  }
  gsStoreData[0] = STORE_DATA_TAG;
  gsStoreData[1] = len;
  memcpy(&gsStoreData[2], pdata, len);
  LSCSTATUS status = LSC_update_seq_handler(Applet_load_seqhandler, name, dest);
  if ((status != LSCSTATUS_SUCCESS) && (gsLsExecuteResp[2] == 0x90) &&
      (gsLsExecuteResp[3] == 0x00)) {
    gsLsExecuteResp[2] = LS_ABORT_SW1;
    gsLsExecuteResp[3] = LS_ABORT_SW2;
  }
  memcpy(&respSW[0], &gsLsExecuteResp[0], 4);
  ALOGD_IF(ese_debug_enabled, "%s: lsExecuteScript Response SW=%2x%2x", fn,
           gsLsExecuteResp[2], gsLsExecuteResp[3]);

  ALOGD_IF(ese_debug_enabled, "%s: exit; status=0x0%x", fn, status);
  return status;
}

/*******************************************************************************
**
** Function:        LSC_update_seq_handler
**
** Description:     Performs the LSC update sequence handler sequence
**
** Returns:         Success if ok.
**
*******************************************************************************/
LSCSTATUS LSC_update_seq_handler(
    LSCSTATUS (*seq_handler[])(Lsc_ImageInfo_t* pContext, LSCSTATUS status,
                               Lsc_TranscieveInfo_t* pInfo),
    const char* name, const char* dest) {
  static const char fn[] = "LSC_update_seq_handler";
  Lsc_ImageInfo_t update_info;

  ALOGD_IF(ese_debug_enabled, "%s: enter", fn);
  memset(&update_info, 0, sizeof(Lsc_ImageInfo_t));
  if (dest != NULL) {
    strcat(update_info.fls_RespPath, dest);
    ALOGD_IF(ese_debug_enabled,
             "%s: Loader Service response data path/destination: %s", fn, dest);
    update_info.bytes_wrote = 0xAA;
  } else {
    update_info.bytes_wrote = 0x55;
  }
  if ((LSC_UpdateExeStatus(LS_DEFAULT_STATUS)) != true) {
    return LSCSTATUS_FAILED;
  }
  // memcpy(update_info.fls_path, (char*)Lsc_path, sizeof(Lsc_path));
  strcat(update_info.fls_path, name);
  ALOGD_IF(ese_debug_enabled, "Selected applet to install is: %s",
           update_info.fls_path);

  uint16_t seq_counter = 0;
  LSCSTATUS status = LSCSTATUS_FAILED;
  Lsc_TranscieveInfo_t trans_info;
  memset(&trans_info, 0, sizeof(Lsc_TranscieveInfo_t));
  while ((seq_handler[seq_counter]) != NULL) {
    status = (*(seq_handler[seq_counter]))(&update_info, status, &trans_info);
    if (LSCSTATUS_SUCCESS != status) {
      ALOGE("%s: exiting; status=0x0%X", fn, status);
      break;
    }
    seq_counter++;
  }

  LSC_CloseChannel(&update_info, LSCSTATUS_FAILED, &trans_info);
  ALOGD_IF(ese_debug_enabled, "%s: exit; status=0x%x", fn, status);
  return status;
}

/*******************************************************************************
**
** Function:        LSC_OpenChannel
**
** Description:     Creates the logical channel with lsc
**
** Returns:         Success if ok.
**
*******************************************************************************/
LSCSTATUS LSC_OpenChannel(Lsc_ImageInfo_t* Os_info, LSCSTATUS status,
                          Lsc_TranscieveInfo_t* pTranscv_Info) {
  static const char fn[] = "LSC_OpenChannel";

  ALOGD_IF(ese_debug_enabled, "%s: enter", fn);
  if (Os_info == NULL || pTranscv_Info == NULL) {
    ALOGE("%s: Invalid parameter", fn);
    return LSCSTATUS_FAILED;
  }
  phNxpEse_data cmdApdu;
  phNxpEse_data rspApdu;
  phNxpEse_memset(&cmdApdu, 0x00, sizeof(phNxpEse_data));
  phNxpEse_memset(&rspApdu, 0x00, sizeof(phNxpEse_data));
  cmdApdu.len = (int32_t)sizeof(OpenChannel);
  cmdApdu.p_data = (uint8_t*)phNxpEse_memalloc(cmdApdu.len * sizeof(uint8_t));
  memcpy(cmdApdu.p_data, OpenChannel, cmdApdu.len);

  ALOGD_IF(ese_debug_enabled, "%s: Calling Secure Element Transceive", fn);
  ESESTATUS eseStat = phNxpEse_Transceive(&cmdApdu, &rspApdu);

  if (eseStat != ESESTATUS_SUCCESS && (rspApdu.len < 0x03)) {
    if (rspApdu.len == 0x02)
      memcpy(&gsLsExecuteResp[2], &rspApdu.p_data[rspApdu.len - 2], 2);
    status = LSCSTATUS_FAILED;
    ALOGE("%s: SE transceive failed status = 0x%X", fn, status);
  } else if (((rspApdu.p_data[rspApdu.len - 2] != 0x90) &&
              (rspApdu.p_data[rspApdu.len - 1] != 0x00))) {
    memcpy(&gsLsExecuteResp[2], &rspApdu.p_data[rspApdu.len - 2], 2);
    status = LSCSTATUS_FAILED;
    ALOGE("%s: invalid response = 0x%X", fn, status);
  } else {
    uint8_t cnt = Os_info->channel_cnt;
    Os_info->Channel_Info[cnt].channel_id = rspApdu.p_data[rspApdu.len - 3];
    Os_info->Channel_Info[cnt].isOpend = true;
    Os_info->channel_cnt++;
    status = LSCSTATUS_SUCCESS;
  }

  phNxpEse_free(cmdApdu.p_data);
  phNxpEse_free(rspApdu.p_data);
  ALOGD_IF(ese_debug_enabled, "%s: exit; status=0x%x", fn, status);
  return status;
}

/*******************************************************************************
**
** Function:        LSC_SelectLsc
**
** Description:     Creates the logical channel with lsc
**                  Channel_id will be used for any communication with Lsc
**
** Returns:         Success if ok.
**
*******************************************************************************/
LSCSTATUS LSC_SelectLsc(Lsc_ImageInfo_t* Os_info, LSCSTATUS status,
                        Lsc_TranscieveInfo_t* pTranscv_Info) {
  static const char fn[] = "LSC_SelectLsc";

  ALOGD_IF(ese_debug_enabled, "%s: enter", fn);

  if (Os_info == NULL || pTranscv_Info == NULL) {
    ALOGE("%s: Invalid parameter", fn);
    return LSCSTATUS_FAILED;
  }

  phNxpEse_data cmdApdu;
  phNxpEse_data rspApdu;

  phNxpEse_memset(&cmdApdu, 0x00, sizeof(phNxpEse_data));
  phNxpEse_memset(&rspApdu, 0x00, sizeof(phNxpEse_data));

  uint8_t selectCnt = 3;
  while ((selectCnt--) > 0) {
    if (selectCnt == 2) {
      cmdApdu.p_data = (uint8_t*)phNxpEse_memalloc(
          ((ArrayOfAIDs[selectCnt - 1][0]) - 1) * sizeof(uint8_t));
      cmdApdu.len = (int32_t)ArrayOfAIDs[selectCnt - 1][0];
    } else {
      cmdApdu.p_data = (uint8_t*)phNxpEse_memalloc(
          ((ArrayOfAIDs[selectCnt][0]) - 1) * sizeof(uint8_t));
      cmdApdu.len = (int32_t)ArrayOfAIDs[selectCnt][0];
    }

    cmdApdu.p_data[0] = Os_info->Channel_Info[0].channel_id;

    memcpy(&(cmdApdu.p_data[1]), &ArrayOfAIDs[selectCnt][2],
           ((ArrayOfAIDs[selectCnt][0]) - 1));

    /*If NFC/SPI Deinitialize requested*/
    ALOGD_IF(ese_debug_enabled,
             "%s: Calling Secure Element Transceive with Loader service AID",
             fn);

    ESESTATUS eseStat = phNxpEse_Transceive(&cmdApdu, &rspApdu);

    if (eseStat != ESESTATUS_SUCCESS && (rspApdu.len == 0x00)) {
      status = LSCSTATUS_FAILED;
      ALOGE("%s: SE transceive failed status = 0x%X", fn, status);
      break;
    } else if (((rspApdu.p_data[rspApdu.len - 2] == 0x90) &&
                (rspApdu.p_data[rspApdu.len - 1] == 0x00))) {
      status = Process_SelectRsp(rspApdu.p_data, (rspApdu.len - 2));
      if (status != LSCSTATUS_SUCCESS) {
        ALOGE("%s: Select Lsc Rsp doesnt have a valid key; status = 0x%X", fn,
              status);
      }
      /*If AID is found which is successfully selected break while loop*/
      if (status == LSCSTATUS_SUCCESS) {
        uint8_t totalLen = ArrayOfAIDs[selectCnt][0];
        uint8_t cnt = 0;
        int32_t wStatus = 0;
        status = LSCSTATUS_FAILED;

        FILE* fAidMem = fopen(AID_MEM_PATH, "w+");

        if (fAidMem == NULL) {
          ALOGE("Error opening AID data file for writing: %s", strerror(errno));
          phNxpEse_free(cmdApdu.p_data);
          return status;
        }
        while (cnt <= totalLen) {
          wStatus = fprintf(fAidMem, "%02x", ArrayOfAIDs[selectCnt][cnt++]);
          if (wStatus != 2) {
            ALOGE("%s: Error writing AID data to AID_MEM file: %s", fn,
                  strerror(errno));
            break;
          }
        }
        if (wStatus == 2) status = LSCSTATUS_SUCCESS;
        fclose(fAidMem);
        break;
      }
    } else if (((rspApdu.p_data[rspApdu.len - 2] != 0x90))) {
      /*Copy the response SW in failure case*/
      memcpy(&gsLsExecuteResp[2], &(rspApdu.p_data[rspApdu.len - 2]), 2);
    } else {
      status = LSCSTATUS_FAILED;
    }
  }
  phNxpEse_free(cmdApdu.p_data);
  phNxpEse_free(rspApdu.p_data);
  ALOGD_IF(ese_debug_enabled, "%s: exit; status=0x%x", fn, status);
  return status;
}

/*******************************************************************************
**
** Function:        LSC_StoreData
**
** Description:     It is used to provide the LSC with an Unique
**                  Identifier of the Application that has triggered the LSC
*script.
**
** Returns:         Success if ok.
**
*******************************************************************************/
LSCSTATUS LSC_StoreData(Lsc_ImageInfo_t* Os_info, LSCSTATUS status,
                        Lsc_TranscieveInfo_t* pTranscv_Info) {
  static const char fn[] = "LSC_StoreData";
  ALOGD_IF(ese_debug_enabled, "%s: enter", fn);
  if (Os_info == NULL || pTranscv_Info == NULL) {
    ALOGE("%s: Invalid parameter", fn);
    return LSCSTATUS_FAILED;
  }

  phNxpEse_data cmdApdu;
  phNxpEse_data rspApdu;
  phNxpEse_memset(&cmdApdu, 0x00, sizeof(phNxpEse_data));
  phNxpEse_memset(&rspApdu, 0x00, sizeof(phNxpEse_data));
  cmdApdu.len = (int32_t)(5 + sizeof(gsStoreData));
  cmdApdu.p_data = (uint8_t*)phNxpEse_memalloc(cmdApdu.len * sizeof(uint8_t));

  uint32_t xx = 0;
  int32_t len =
      gsStoreData[1] + 2;  //+2 offset is for tag value and length byte
  cmdApdu.p_data[xx++] = STORE_DATA_CLA | (Os_info->Channel_Info[0].channel_id);
  cmdApdu.p_data[xx++] = STORE_DATA_INS;
  cmdApdu.p_data[xx++] = 0x00;  // P1
  cmdApdu.p_data[xx++] = 0x00;  // P2
  cmdApdu.p_data[xx++] = len;
  memcpy(&(cmdApdu.p_data[xx]), gsStoreData, len);

  ALOGD_IF(ese_debug_enabled, "%s: Calling Secure Element Transceive", fn);
  ESESTATUS eseStat = phNxpEse_Transceive(&cmdApdu, &rspApdu);

  if ((eseStat != ESESTATUS_SUCCESS) && (rspApdu.len == 0x00)) {
    status = LSCSTATUS_FAILED;
    ALOGE("%s: SE transceive failed status = 0x%X", fn, status);
  } else if ((rspApdu.p_data[rspApdu.len - 2] == 0x90) &&
             (rspApdu.p_data[rspApdu.len - 1] == 0x00)) {
    ALOGD_IF(ese_debug_enabled, "%s: STORE CMD is successful", fn);
    status = LSCSTATUS_SUCCESS;
  } else {
    /*Copy the response SW in failure case*/
    memcpy(&gsLsExecuteResp[2], &(rspApdu.p_data[rspApdu.len - 2]), 2);
    status = LSCSTATUS_FAILED;
  }
  phNxpEse_free(cmdApdu.p_data);
  phNxpEse_free(rspApdu.p_data);
  ALOGD_IF(ese_debug_enabled, "%s: exit; status=0x%x", fn, status);
  return status;
}

/*******************************************************************************
**
** Function:        LSC_loadapplet
**
** Description:     Reads the script from the file and sent to Lsc
**
** Returns:         Success if ok.
**
*******************************************************************************/
LSCSTATUS LSC_loadapplet(Lsc_ImageInfo_t* Os_info, LSCSTATUS status,
                         Lsc_TranscieveInfo_t* pTranscv_Info) {
  static const char fn[] = "LSC_loadapplet";
  bool reachEOFCheck = false;

  ALOGD_IF(ese_debug_enabled, "%s: enter", fn);
  if (Os_info == NULL || pTranscv_Info == NULL) {
    ALOGE("%s: Invalid parameter", fn);
    return LSCSTATUS_FAILED;
  }
  if (Os_info->bytes_wrote == 0xAA) {
    Os_info->fResp = fopen(Os_info->fls_RespPath, "a+");
    if (Os_info->fResp == NULL) {
      ALOGE("%s: Error opening response recording file <%s> for reading: %s",
            fn, Os_info->fls_path, strerror(errno));
      return LSCSTATUS_FAILED;
    }
    ALOGD_IF(ese_debug_enabled,
             "%s: Response OUT FILE path is successfully created", fn);
  } else {
    ALOGD_IF(ese_debug_enabled,
             "%s: Response Out file is optional as per input", fn);
  }

  Os_info->fp = fopen(Os_info->fls_path, "r");
  if (Os_info->fp == NULL) {
    ALOGE("%s: Error opening OS image file <%s> for reading: %s", fn,
          Os_info->fls_path, strerror(errno));
    return LSCSTATUS_FAILED;
  }
  int wResult = fseek(Os_info->fp, 0L, SEEK_END);
  if (wResult) {
    ALOGE("%s: Error seeking end OS image file %s", fn, strerror(errno));
    goto exit;
  }
  Os_info->fls_size = ftell(Os_info->fp);
  if (Os_info->fls_size < 0) {
    ALOGE("%s: Error ftelling file %s", fn, strerror(errno));
    goto exit;
  }
  wResult = fseek(Os_info->fp, 0L, SEEK_SET);
  if (wResult) {
    ALOGE("%s: Error seeking start image file %s", fn, strerror(errno));
    goto exit;
  }

  Os_info->bytes_read = 0;
  status = LSC_Check_KeyIdentifier(Os_info, status, pTranscv_Info, NULL,
                                   LSCSTATUS_FAILED, 0);
  if (status != LSCSTATUS_SUCCESS) {
    goto exit;
  }

  uint8_t len_byte, offset;
  while (!feof(Os_info->fp) && (Os_info->bytes_read < Os_info->fls_size)) {
    len_byte = 0;
    offset = 0;
    /*Check if the certificate/ is verified or not*/
    if (status != LSCSTATUS_SUCCESS) {
      goto exit;
    }

    uint8_t temp_buf[1024];
    memset(temp_buf, 0, sizeof(temp_buf));
    status = LSC_ReadScript(Os_info, temp_buf);
    if (status != LSCSTATUS_SUCCESS) {
      goto exit;
    }
    /*Reset the flag in case further commands exists*/
    reachEOFCheck = false;

    int32_t wLen = 0;
    LSCSTATUS tag40_found = LSCSTATUS_SUCCESS;
    if (temp_buf[offset] == TAG_LSC_CMD_ID) {
      /* start sending the packet to Lsc */
      offset = offset + 1;
      len_byte = Numof_lengthbytes(&temp_buf[offset], &wLen);
      /* If the len data not present or len is less than or equal to 32 */
      if ((len_byte == 0) || (wLen <= 32)) {
        ALOGE("%s: Invalid length zero", fn);
        goto exit;
      }

      tag40_found = LSCSTATUS_SUCCESS;
      offset = offset + len_byte;
      pTranscv_Info->sSendlength = wLen;
      memcpy(pTranscv_Info->sSendData, &temp_buf[offset], wLen);

      status = LSC_SendtoLsc(Os_info, status, pTranscv_Info, LS_Comm);
      if (status != LSCSTATUS_SUCCESS) {
        /*When the switching of LS 6320 case*/
        if (status == LSCSTATUS_FILE_NOT_FOUND) {
          /*When 6320 occurs close the existing channels*/
          LSC_CloseChannel(Os_info, status, pTranscv_Info);

          status = LSCSTATUS_FAILED;
          status = LSC_OpenChannel(Os_info, status, pTranscv_Info);
          if (status == LSCSTATUS_SUCCESS) {
            ALOGD_IF(ese_debug_enabled,
                     "%s: SUCCESS:Post Switching LS open channel", fn);
            status = LSCSTATUS_FAILED;
            status = LSC_SelectLsc(Os_info, status, pTranscv_Info);
            if (status == LSCSTATUS_SUCCESS) {
              ALOGD_IF(ese_debug_enabled,
                       "%s: SUCCESS:Post Switching LS select", fn);
              status = LSCSTATUS_FAILED;
              status = LSC_StoreData(Os_info, status, pTranscv_Info);
              if (status == LSCSTATUS_SUCCESS) {
                /*Enable certificate and signature verification*/
                tag40_found = LSCSTATUS_SUCCESS;
                gsLsExecuteResp[2] = 0x90;
                gsLsExecuteResp[3] = 0x00;
                reachEOFCheck = true;
                continue;
              }
              ALOGE("%s: Post Switching LS store data failure", fn);
            }
            ALOGE("%s: Post Switching LS select failure", fn);
          }
          ALOGE("%s: Post Switching LS failure", fn);
        }
        ALOGE("%s: Sending packet to lsc failed", fn);
        goto exit;
      }
    } else if ((temp_buf[offset] == (0x7F)) &&
               (temp_buf[offset + 1] == (0x21))) {
      ALOGD_IF(ese_debug_enabled,
               "%s: TAGID: Encountered again certificate tag 7F21", fn);
      if (tag40_found == LSCSTATUS_SUCCESS) {
        ALOGD_IF(ese_debug_enabled,
                 "%s: 2nd Script processing starts with reselect", fn);
        status = LSCSTATUS_FAILED;
        status = LSC_SelectLsc(Os_info, status, pTranscv_Info);
        if (status == LSCSTATUS_SUCCESS) {
          ALOGD_IF(ese_debug_enabled,
                   "%s: 2nd Script select success next store data command", fn);
          status = LSCSTATUS_FAILED;
          status = LSC_StoreData(Os_info, status, pTranscv_Info);
          if (status == LSCSTATUS_SUCCESS) {
            ALOGD_IF(ese_debug_enabled,
                     "%s: 2nd Script store data success next certificate "
                     "verification",
                     fn);
            offset = offset + 2;
            len_byte = Numof_lengthbytes(&temp_buf[offset], &wLen);
            status = LSC_Check_KeyIdentifier(Os_info, status, pTranscv_Info,
                                             temp_buf, LSCSTATUS_SUCCESS,
                                             wLen + len_byte + 2);
          }
        }
        /*If the certificate and signature is verified*/
        if (status == LSCSTATUS_SUCCESS) {
          /*If the certificate is verified for 6320 then new script starts*/
          tag40_found = LSCSTATUS_FAILED;
        } else {
          /*If the certificate or signature verification failed*/
          goto exit;
        }
      } else {
        /*Already certificate&Sginature verified previously skip 7f21& tag 60*/
        memset(temp_buf, 0, sizeof(temp_buf));
        status = LSC_ReadScript(Os_info, temp_buf);
        if (status != LSCSTATUS_SUCCESS) {
          ALOGE("%s: Next Tag has to TAG 60 not found", fn);
          goto exit;
        }
        if (temp_buf[offset] == TAG_JSBL_HDR_ID)
          continue;
        else
          goto exit;
      }
    } else {
      /*
       * Invalid packet received in between stop processing packet
       * return failed status
       */
      status = LSCSTATUS_FAILED;
      break;
    }
  }
  if (Os_info->bytes_wrote == 0xAA) {
    fclose(Os_info->fResp);
  }
  LSC_UpdateExeStatus(LS_SUCCESS_STATUS);
  wResult = fclose(Os_info->fp);
  ALOGD_IF(ese_debug_enabled, "%s: exit, status=0x%x", fn, status);
  return status;
exit:
  wResult = fclose(Os_info->fp);
  if (Os_info->bytes_wrote == 0xAA) {
    fclose(Os_info->fResp);
  }
  /*Script ends with SW 6320 and reached END OF FILE*/
  if (reachEOFCheck == true) {
    status = LSCSTATUS_SUCCESS;
    LSC_UpdateExeStatus(LS_SUCCESS_STATUS);
  }
  ALOGD_IF(ese_debug_enabled, "%s: exit; status= 0x%X", fn, status);
  return status;
}

/*******************************************************************************
**
** Function:        LSC_Check_KeyIdentifier
**
** Description:     Checks and validates certificate
**
** Returns:         Success if ok.
**
*******************************************************************************/
LSCSTATUS LSC_Check_KeyIdentifier(Lsc_ImageInfo_t* Os_info, LSCSTATUS status,
                                  Lsc_TranscieveInfo_t* pTranscv_Info,
                                  uint8_t* temp_buf, LSCSTATUS flag,
                                  int32_t wNewLen) {
  static const char fn[] = "LSC_Check_KeyIdentifier";
  status = LSCSTATUS_FAILED;
  uint8_t read_buf[1024];
  uint16_t offset = 0, len_byte = 0;
  int32_t wLen;
  uint8_t certf_found = LSCSTATUS_FAILED;

  ALOGD_IF(ese_debug_enabled, "%s: enter", fn);

  while (!feof(Os_info->fp) && (Os_info->bytes_read < Os_info->fls_size)) {
    offset = 0x00;
    wLen = 0;
    if (flag == LSCSTATUS_SUCCESS) {
      /*If the 7F21 TAG is already read: After TAG 40*/
      memcpy(read_buf, temp_buf, wNewLen);
      status = LSCSTATUS_SUCCESS;
      flag = LSCSTATUS_FAILED;
    } else {
      /*If the 7F21 TAG is not read: Before TAG 40*/
      status = LSC_ReadScript(Os_info, read_buf);
    }
    if (status != LSCSTATUS_SUCCESS) return status;
    if (LSCSTATUS_SUCCESS ==
        Check_Complete_7F21_Tag(Os_info, pTranscv_Info, read_buf, &offset)) {
      ALOGD_IF(ese_debug_enabled, "%s: Certificate is verified", fn);
      certf_found = LSCSTATUS_SUCCESS;
      break;
    }
    /*
     * The Loader Service Client ignores all subsequent commands starting by tag
     * 7F21 or tag 60 until the first command starting by tag 40 is found
     */
    else if (((read_buf[offset] == TAG_LSC_CMD_ID) &&
              (certf_found != LSCSTATUS_SUCCESS))) {
      ALOGE("%s: NOT FOUND Root entity identifier's certificate", fn);
      status = LSCSTATUS_FAILED;
      return status;
    }
  }
  memset(read_buf, 0, sizeof(read_buf));
  if (certf_found == LSCSTATUS_SUCCESS) {
    offset = 0x00;
    wLen = 0;
    status = LSC_ReadScript(Os_info, read_buf);
    if (status != LSCSTATUS_SUCCESS) return status;
    if ((read_buf[offset] == TAG_JSBL_HDR_ID) &&
        (certf_found != LSCSTATUS_FAILED)) {
      // TODO check the SElect cmd response and return status accordingly
      ALOGD_IF(ese_debug_enabled, "%s: TAGID: TAG_JSBL_HDR_ID", fn);
      offset = offset + 1;
      len_byte = Numof_lengthbytes(&read_buf[offset], &wLen);
      offset = offset + len_byte;
      if (read_buf[offset] == TAG_SIGNATURE_ID) {
        offset = offset + 1;
        len_byte = Numof_lengthbytes(&read_buf[offset], &wLen);
        offset = offset + len_byte;
        ALOGD_IF(ese_debug_enabled, "%s: TAGID: TAG_SIGNATURE_ID", fn);

        pTranscv_Info->sSendlength = wLen + 5;

        pTranscv_Info->sSendData[0] = 0x00;
        pTranscv_Info->sSendData[1] = 0xA0;
        pTranscv_Info->sSendData[2] = 0x00;
        pTranscv_Info->sSendData[3] = 0x00;
        pTranscv_Info->sSendData[4] = wLen;

        memcpy(&(pTranscv_Info->sSendData[5]), &read_buf[offset], wLen);
        ALOGD_IF(ese_debug_enabled, "%s: start transceive for length %ld", fn,
                 (long)pTranscv_Info->sSendlength);
        status = LSC_SendtoLsc(Os_info, status, pTranscv_Info, LS_Sign);
        if (status != LSCSTATUS_SUCCESS) {
          return status;
        }
      }
    } else if (read_buf[offset] != TAG_JSBL_HDR_ID) {
      status = LSCSTATUS_FAILED;
    }
  } else {
    ALOGE("%s : Exit certificate verification failed", fn);
  }

  ALOGD_IF(ese_debug_enabled, "%s: exit: status=0x%x", fn, status);
  return status;
}

/*******************************************************************************
**
** Function:        LSC_ReadScript
**
** Description:     Reads the current line if the script
**
** Returns:         Success if ok.
**
*******************************************************************************/
LSCSTATUS LSC_ReadScript(Lsc_ImageInfo_t* Os_info, uint8_t* read_buf) {
  static const char fn[] = "LSC_ReadScript";
  int32_t wResult = 0, wCount, wIndex = 0;

  ALOGD_IF(ese_debug_enabled, "%s: enter", fn);

  for (wCount = 0; (wCount < 2 && !feof(Os_info->fp)); wCount++, wIndex++) {
    wResult = FSCANF_BYTE(Os_info->fp, "%2X", (unsigned int*)&read_buf[wIndex]);
  }
  if (wResult == 0) return LSCSTATUS_FAILED;

  Os_info->bytes_read = Os_info->bytes_read + (wCount * 2);

  int32_t lenOff = 1;
  if ((read_buf[0] == 0x7f) && (read_buf[1] == 0x21)) {
    for (wCount = 0; (wCount < 1 && !feof(Os_info->fp)); wCount++, wIndex++) {
      wResult =
          FSCANF_BYTE(Os_info->fp, "%2X", (unsigned int*)&read_buf[wIndex]);
    }
    if (wResult == 0) {
      ALOGE("%s: Exit Read Script failed in 7F21 ", fn);
      return LSCSTATUS_FAILED;
    }
    /*Read_Script from wCount*2 to wCount*1 */
    Os_info->bytes_read = Os_info->bytes_read + (wCount * 2);
    lenOff = 2;
  } else if ((read_buf[0] == 0x40) || (read_buf[0] == 0x60)) {
    lenOff = 1;
  } else {
    /*If TAG is neither 7F21 nor 60 nor 40 then ABORT execution*/
    ALOGE("%s: Invalid TAG 0x%X found in the script", fn, read_buf[0]);
    return LSCSTATUS_FAILED;
  }

  uint8_t len_byte = 0;
  int32_t wLen;
  if (read_buf[lenOff] == 0x00) {
    ALOGE("%s: Invalid length zero", fn);
    len_byte = 0x00;
    return LSCSTATUS_FAILED;
  } else if ((read_buf[lenOff] & 0x80) == 0x80) {
    len_byte = read_buf[lenOff] & 0x0F;
    len_byte = len_byte + 1;  // 1 byte added for byte 0x81

    ALOGD_IF(ese_debug_enabled, "%s: Length byte Read from 0x80 is 0x%x ", fn,
             len_byte);

    if (len_byte == 0x02) {
      for (wCount = 0; (wCount < 1 && !feof(Os_info->fp)); wCount++, wIndex++) {
        wResult =
            FSCANF_BYTE(Os_info->fp, "%2X", (unsigned int*)&read_buf[wIndex]);
      }
      if (wResult == 0) {
        ALOGE("%s: Exit Read Script failed in length 0x02 ", fn);
        return LSCSTATUS_FAILED;
      }

      wLen = read_buf[lenOff + 1];
      Os_info->bytes_read = Os_info->bytes_read + (wCount * 2);
      ALOGD_IF(ese_debug_enabled,
               "%s: Length of Read Script in len_byte= 0x02 is 0x%x ", fn,
               wLen);
    } else if (len_byte == 0x03) {
      for (wCount = 0; (wCount < 2 && !feof(Os_info->fp)); wCount++, wIndex++) {
        wResult =
            FSCANF_BYTE(Os_info->fp, "%2X", (unsigned int*)&read_buf[wIndex]);
      }
      if (wResult == 0) {
        ALOGE("%s: Exit Read Script failed in length 0x03 ", fn);
        return LSCSTATUS_FAILED;
      }

      Os_info->bytes_read = Os_info->bytes_read + (wCount * 2);
      wLen = read_buf[lenOff + 1];  // Length of the packet send to LSC
      wLen = ((wLen << 8) | (read_buf[lenOff + 2]));
      ALOGD_IF(ese_debug_enabled,
               "%s: Length of Read Script in len_byte= 0x03 is 0x%x ", fn,
               wLen);
    } else {
      /*Need to provide the support if length is more than 2 bytes*/
      ALOGE("Length recived is greater than 3");
      return LSCSTATUS_FAILED;
    }
  } else {
    len_byte = 0x01;
    wLen = read_buf[lenOff];
    ALOGE("%s: Length of Read Script in len_byte= 0x01 is 0x%x ", fn, wLen);
  }

  for (wCount = 0; (wCount < wLen && !feof(Os_info->fp)); wCount++, wIndex++) {
    wResult = FSCANF_BYTE(Os_info->fp, "%2X", (unsigned int*)&read_buf[wIndex]);
  }

  if (wResult == 0) {
    ALOGE("%s: Exit Read Script failed in fscanf function ", fn);
    return LSCSTATUS_FAILED;
  }
  Os_info->bytes_read =
      Os_info->bytes_read + (wCount * 2) + 1;  // not sure why 2 added

  ALOGD_IF(ese_debug_enabled, "%s: exit: Num of bytes read=%d and index=%d", fn,
           Os_info->bytes_read, wIndex);

  return LSCSTATUS_SUCCESS;
}

/*******************************************************************************
**
** Function:        LSC_SendtoEse
**
** Description:     It is used to send the packet to p61
**
** Returns:         Success if ok.
**
*******************************************************************************/
LSCSTATUS LSC_SendtoEse(Lsc_ImageInfo_t* Os_info, LSCSTATUS status,
                        Lsc_TranscieveInfo_t* pTranscv_Info) {
  static const char fn[] = "LSC_SendtoEse";
  bool chanl_open_cmd = false;

  ALOGD_IF(ese_debug_enabled, "%s: enter", fn);

  /* Bufferize_load_cmds function is implemented in JCOP */
  status = Bufferize_load_cmds(Os_info, status, pTranscv_Info);
  if (status != LSCSTATUS_FAILED) {
    if (pTranscv_Info->sSendData[1] == 0x70) {
      if (pTranscv_Info->sSendData[2] == 0x00) {
        chanl_open_cmd = true;
      } else {
        for (uint8_t cnt = 0; cnt < Os_info->channel_cnt; cnt++) {
          if (Os_info->Channel_Info[cnt].channel_id ==
              pTranscv_Info->sSendData[3]) {
            ALOGD_IF(ese_debug_enabled, "%s: channel 0%x closed", fn,
                     Os_info->Channel_Info[cnt].channel_id);
            Os_info->Channel_Info[cnt].isOpend = false;
          }
        }
      }
    }

    phNxpEse_data cmdApdu;
    phNxpEse_data rspApdu;
    phNxpEse_memset(&cmdApdu, 0x00, sizeof(phNxpEse_data));
    phNxpEse_memset(&rspApdu, 0x00, sizeof(phNxpEse_data));

    cmdApdu.len = (int32_t)(pTranscv_Info->sSendlength);
    cmdApdu.p_data = (uint8_t*)phNxpEse_memalloc(cmdApdu.len * sizeof(uint8_t));
    memcpy(cmdApdu.p_data, pTranscv_Info->sSendData, cmdApdu.len);

    ESESTATUS eseStat = phNxpEse_Transceive(&cmdApdu, &rspApdu);

    if (eseStat != ESESTATUS_SUCCESS) {
      ALOGE("%s: Transceive failed; status=0x%X", fn, eseStat);
      status = LSCSTATUS_FAILED;
    } else {
      if (chanl_open_cmd && (rspApdu.len == 0x03) &&
          ((rspApdu.p_data[rspApdu.len - 2] == 0x90) &&
           (rspApdu.p_data[rspApdu.len - 1] == 0x00))) {
        ALOGD_IF(ese_debug_enabled, "%s: open channel success", fn);
        uint8_t cnt = Os_info->channel_cnt;
        Os_info->Channel_Info[cnt].channel_id = rspApdu.p_data[rspApdu.len - 3];
        Os_info->Channel_Info[cnt].isOpend = true;
        Os_info->channel_cnt++;
      }
      memcpy(pTranscv_Info->sRecvData, rspApdu.p_data, rspApdu.len);
      status = Process_EseResponse(pTranscv_Info, rspApdu.len, Os_info);
      phNxpEse_free(cmdApdu.p_data);
      phNxpEse_free(rspApdu.p_data);
    }
  } else if (gsSendBack_cmds == false) {
    /* Workaround for issue in JCOP, send the fake response back */
    int32_t recvBufferActualSize = 0x03;
    pTranscv_Info->sRecvData[0] = 0x00;
    pTranscv_Info->sRecvData[1] = 0x90;
    pTranscv_Info->sRecvData[2] = 0x00;
    status = Process_EseResponse(pTranscv_Info, recvBufferActualSize, Os_info);
  } else {
    if (gsIslastcmdLoad == true) {
      status = Send_Backall_Loadcmds(Os_info, status, pTranscv_Info);
      gsSendBack_cmds = false;
    } else {
      memset(gsCmd_Buffer, 0, sizeof(gsCmd_Buffer));
      gsSendBack_cmds = false;
      status = LSCSTATUS_FAILED;
    }
  }

  ALOGD_IF(ese_debug_enabled, "%s: exit: status=0x%x", fn, status);
  return status;
}

/*******************************************************************************
**
** Function:        LSC_SendtoLsc
**
** Description:     It is used to forward the packet to Lsc
**
** Returns:         Success if ok.
**
*******************************************************************************/
LSCSTATUS LSC_SendtoLsc(Lsc_ImageInfo_t* Os_info, LSCSTATUS status,
                        Lsc_TranscieveInfo_t* pTranscv_Info, Ls_TagType tType) {
  static const char fn[] = "LSC_SendtoLsc";

  ALOGD_IF(ese_debug_enabled, "%s: enter", fn);
  pTranscv_Info->sSendData[0] = (0x80 | Os_info->Channel_Info[0].channel_id);
  pTranscv_Info->timeout = gsTransceiveTimeout;
  pTranscv_Info->sRecvlength = 1024;

  phNxpEse_data cmdApdu;
  phNxpEse_data rspApdu;
  phNxpEse_memset(&cmdApdu, 0x00, sizeof(phNxpEse_data));
  phNxpEse_memset(&rspApdu, 0x00, sizeof(phNxpEse_data));
  cmdApdu.len = pTranscv_Info->sSendlength;
  cmdApdu.p_data = (uint8_t*)phNxpEse_memalloc(cmdApdu.len * sizeof(uint8_t));
  memcpy(cmdApdu.p_data, pTranscv_Info->sSendData, cmdApdu.len);

  ESESTATUS eseStat = phNxpEse_Transceive(&cmdApdu, &rspApdu);

  if (eseStat != ESESTATUS_SUCCESS) {
    ALOGE("%s: Transceive failed; status=0x%X", fn, eseStat);
    status = LSCSTATUS_FAILED;
  } else {
    memcpy(pTranscv_Info->sRecvData, rspApdu.p_data, rspApdu.len);
    status = LSC_ProcessResp(Os_info, rspApdu.len, pTranscv_Info, tType);
  }
  phNxpEse_free(cmdApdu.p_data);
  phNxpEse_free(rspApdu.p_data);
  ALOGD_IF(ese_debug_enabled, "%s: exit: status=0x%x", fn, status);
  return status;
}

/*******************************************************************************
**
** Function:        LSC_CloseChannel
**
** Description:     Closes the previously opened logical channel
**
** Returns:         Success if ok.
**
*******************************************************************************/
LSCSTATUS LSC_CloseChannel(Lsc_ImageInfo_t* Os_info, LSCSTATUS status,
                           Lsc_TranscieveInfo_t* pTranscv_Info) {
  static const char fn[] = "LSC_CloseChannel";
  status = LSCSTATUS_FAILED;

  ALOGD_IF(ese_debug_enabled, "%s: enter", fn);

  if (Os_info == NULL || pTranscv_Info == NULL) {
    ALOGE("%s: Invalid parameter", fn);
    return LSCSTATUS_FAILED;
  }
  for (uint8_t cnt = 0; (cnt < Os_info->channel_cnt); cnt++) {
    phNxpEse_data cmdApdu;
    phNxpEse_data rspApdu;

    phNxpEse_memset(&cmdApdu, 0x00, sizeof(phNxpEse_data));
    phNxpEse_memset(&rspApdu, 0x00, sizeof(phNxpEse_data));

    cmdApdu.len = 5;
    cmdApdu.p_data = (uint8_t*)phNxpEse_memalloc(cmdApdu.len * sizeof(uint8_t));
    if (!Os_info->Channel_Info[cnt].isOpend) continue;
    uint8_t xx = 0;
    cmdApdu.p_data[xx++] = Os_info->Channel_Info[cnt].channel_id;
    cmdApdu.p_data[xx++] = 0x70;
    cmdApdu.p_data[xx++] = 0x80;
    cmdApdu.p_data[xx++] = Os_info->Channel_Info[cnt].channel_id;
    cmdApdu.p_data[xx++] = 0x00;

    ESESTATUS eseStat = phNxpEse_Transceive(&cmdApdu, &rspApdu);

    if (eseStat != ESESTATUS_SUCCESS || rspApdu.len < 2) {
      ALOGD_IF(ese_debug_enabled, "%s: Transceive failed; status=0x%X", fn,
               eseStat);
    } else if ((rspApdu.p_data[rspApdu.len - 2] == 0x90) &&
               (rspApdu.p_data[rspApdu.len - 1] == 0x00)) {
      ALOGD_IF(ese_debug_enabled, "%s: Close channel id = 0x0%x success", fn,
               Os_info->Channel_Info[cnt].channel_id);
      status = LSCSTATUS_SUCCESS;
    } else {
      ALOGD_IF(ese_debug_enabled, "%s: Close channel id = 0x0%x failed", fn,
               Os_info->Channel_Info[cnt].channel_id);
    }
    phNxpEse_free(cmdApdu.p_data);
    phNxpEse_free(rspApdu.p_data);
  }
  ALOGD_IF(ese_debug_enabled, "%s: exit; status=0x0%x", fn, status);
  return status;
}

/*******************************************************************************
**
** Function:        LSC_ProcessResp
**
** Description:     Process the response packet received from Lsc
**
** Returns:         Success if ok.
**
*******************************************************************************/
LSCSTATUS LSC_ProcessResp(Lsc_ImageInfo_t* image_info, int32_t recvlen,
                          Lsc_TranscieveInfo_t* trans_info, Ls_TagType tType) {
  static const char fn[] = "LSC_ProcessResp";
  uint8_t* RecvData = trans_info->sRecvData;

  ALOGD_IF(ese_debug_enabled, "%s: enter", fn);

  if (RecvData == NULL && recvlen == 0x00) {
    ALOGE("%s: Invalid parameter.", fn);
    return LSCSTATUS_FAILED;
  } else if (recvlen < 2) {
    ALOGE("%s: Invalid response.", fn);
    return LSCSTATUS_FAILED;
  }

  char sw[2];
  sw[0] = RecvData[recvlen - 2];
  sw[1] = RecvData[recvlen - 1];
  ALOGD_IF(ese_debug_enabled, "%s: Process Response SW, status = 0x%2X%2X", fn,
           sw[0], sw[1]);

  /*Update the Global variable for storing response length*/
  gsResp_len = recvlen;
  if (sw[0] != 0x63) {
    gsLsExecuteResp[2] = sw[0];
    gsLsExecuteResp[3] = sw[1];
  }

  LSCSTATUS status = LSCSTATUS_FAILED;
  if ((recvlen == 0x02) && (sw[0] == 0x90) && (sw[1] == 0x00)) {
    status = Write_Response_To_OutFile(image_info, RecvData, recvlen, tType);
  } else if ((recvlen > 0x02) && (sw[0] == 0x90) && (sw[1] == 0x00)) {
    status = Write_Response_To_OutFile(image_info, RecvData, recvlen, tType);
  } else if ((recvlen > 0x02) && (sw[0] == 0x63) && (sw[1] == 0x10)) {
    static int32_t temp_len = 0;
    if (temp_len != 0) {
      memcpy((trans_info->sTemp_recvbuf + temp_len), RecvData, (recvlen - 2));
      trans_info->sSendlength = temp_len + (recvlen - 2);
      memcpy(trans_info->sSendData, trans_info->sTemp_recvbuf,
             trans_info->sSendlength);
      temp_len = 0;
    } else {
      memcpy(trans_info->sSendData, RecvData, (recvlen - 2));
      trans_info->sSendlength = recvlen - 2;
    }
    status = LSC_SendtoEse(image_info, status, trans_info);
  } else if ((recvlen > 0x02) && (sw[0] == 0x63) && (sw[1] == 0x20)) {
    uint8_t aid_array[22];
    aid_array[0] = recvlen + 3;
    aid_array[1] = 00;
    aid_array[2] = 0xA4;
    aid_array[3] = 0x04;
    aid_array[4] = 0x00;
    aid_array[5] = recvlen - 2;
    memcpy(&aid_array[6], &RecvData[0], recvlen - 2);
    memcpy(&ArrayOfAIDs[2][0], &aid_array[0], recvlen + 4);

    FILE* fAidMem = fopen(AID_MEM_PATH, "w");

    if (fAidMem == NULL) {
      ALOGE("%s: Error opening AID data for writing: %s", fn, strerror(errno));
      return LSCSTATUS_FAILED;
    }

    /*Updating the AID_MEM with new value into AID file*/
    uint8_t respLen = 0;
    int32_t wStatus = 0;
    while (respLen <= (recvlen + 4)) {
      wStatus = fprintf(fAidMem, "%2x", aid_array[respLen++]);
      if (wStatus != 2) {
        ALOGE("%s: Invalid Response during fprintf; status=0x%x", fn, wStatus);
        fclose(fAidMem);
        break;
      }
    }
    if (wStatus == 2) {
      status = LSCSTATUS_FILE_NOT_FOUND;
    } else {
      status = LSCSTATUS_FAILED;
    }
  } else if ((recvlen >= 0x02) &&
             ((sw[0] != 0x90) && (sw[0] != 0x63) && (sw[0] != 0x61))) {
    Write_Response_To_OutFile(image_info, RecvData, recvlen, tType);
  }
  ALOGD_IF(ese_debug_enabled, "%s: exit: status=0x%x", fn, status);
  return status;
}

/*******************************************************************************
**
** Function:        Process_EseResponse
**
** Description:     It is used to process the received response packet from ESE
**
** Returns:         Success if ok.
**
*******************************************************************************/
LSCSTATUS Process_EseResponse(Lsc_TranscieveInfo_t* pTranscv_Info,
                              int32_t recv_len, Lsc_ImageInfo_t* Os_info) {
  static const char fn[] = "Process_EseResponse";
  LSCSTATUS status = LSCSTATUS_SUCCESS;
  uint8_t xx = 0;
  ALOGD_IF(ese_debug_enabled, "%s: enter", fn);

  pTranscv_Info->sSendData[xx++] =
      (CLA_BYTE | Os_info->Channel_Info[0].channel_id);
  pTranscv_Info->sSendData[xx++] = 0xA2;

  if (recv_len <= 0xFF) {
    pTranscv_Info->sSendData[xx++] = 0x80;
    pTranscv_Info->sSendData[xx++] = 0x00;
    pTranscv_Info->sSendData[xx++] = (uint8_t)recv_len;
    memcpy(&(pTranscv_Info->sSendData[xx]), pTranscv_Info->sRecvData, recv_len);
    pTranscv_Info->sSendlength = xx + recv_len;
    status = LSC_SendtoLsc(Os_info, status, pTranscv_Info, LS_Comm);
  } else {
    while (recv_len > MAX_SIZE) {
      xx = PARAM_P1_OFFSET;
      pTranscv_Info->sSendData[xx++] = 0x00;
      pTranscv_Info->sSendData[xx++] = 0x00;
      pTranscv_Info->sSendData[xx++] = MAX_SIZE;
      recv_len = recv_len - MAX_SIZE;
      memcpy(&(pTranscv_Info->sSendData[xx]), pTranscv_Info->sRecvData,
             MAX_SIZE);
      pTranscv_Info->sSendlength = xx + MAX_SIZE;
      /*
       * Need not store Process eSE response's response in the out file so
       * LS_Comm = 0
       */
      status = LSC_SendtoLsc(Os_info, status, pTranscv_Info, LS_Comm);
      if (status != LSCSTATUS_SUCCESS) {
        ALOGE("%s: Sending packet to Lsc failed: status=0x%x", fn, status);
        return status;
      }
    }
    xx = PARAM_P1_OFFSET;
    pTranscv_Info->sSendData[xx++] = LAST_BLOCK;
    pTranscv_Info->sSendData[xx++] = 0x01;
    pTranscv_Info->sSendData[xx++] = recv_len;
    memcpy(&(pTranscv_Info->sSendData[xx]), pTranscv_Info->sRecvData, recv_len);
    pTranscv_Info->sSendlength = xx + recv_len;
    status = LSC_SendtoLsc(Os_info, status, pTranscv_Info, LS_Comm);
  }
  ALOGD_IF(ese_debug_enabled, "%s: exit: status=0x%x", fn, status);
  return status;
}

/*******************************************************************************
**
** Function:        Process_SelectRsp
**
** Description:    It is used to process the received response for SELECT LSC
**                 cmd.
**
** Returns:         Success if ok.
**
*******************************************************************************/
LSCSTATUS Process_SelectRsp(uint8_t* Recv_data, int32_t Recv_len) {
  static const char fn[] = "Process_SelectRsp";
  ALOGD_IF(ese_debug_enabled, "%s: enter", fn);

  if (Recv_len < 2) {
    ALOGE("%s: Invalid response length %d", fn, Recv_len);
    return LSCSTATUS_FAILED;
  }

  int i = 0;
  if (Recv_data[i] != TAG_SELECT_ID) {
    ALOGE("%s: Invalid FCI TAG = 0x%x", fn, Recv_data[i]);
    return LSCSTATUS_FAILED;
  }
  i++;
  int len = Recv_data[i++];
  if (Recv_len < len + 2) {
    ALOGE("%s: Invalid response length %d", fn, Recv_len);
    return LSCSTATUS_FAILED;
  }
  if (Recv_data[i] != TAG_LSC_ID) {
    ALOGE("%s: Invalid Loader Service AID TAG ID = 0x%x", fn, Recv_data[i]);
    return LSCSTATUS_FAILED;
  }
  i++;
  len = Recv_data[i];
  i = i + 1 + len;  // points to next tag name A5
  // points to TAG 9F08 for LS application version
  if ((Recv_data[i] != TAG_LS_VER1) || (Recv_data[i + 1] != TAG_LS_VER2)) {
    ALOGE("%s: Invalid LS Version = 0x%2X%2X", fn, Recv_data[i],
          Recv_data[i + 1]);
    return LSCSTATUS_FAILED;
  }
  uint8_t lsaVersionLen = 0;
  i = i + 2;
  lsaVersionLen = Recv_data[i];
  // points to TAG 9F08 LS application version
  i++;
  // points to Identifier of the Root Entity key set identifier
  i = i + lsaVersionLen;

  if (Recv_data[i] != TAG_RE_KEYID) {
    ALOGE("%s: Invalid Root entity key set TAG ID = 0x%x", fn, Recv_data[i]);
    return LSCSTATUS_FAILED;
  }

  i = i + 2;
  if (Recv_data[i] != TAG_LSRE_ID) {
    ALOGE("%s: Invalid Root entity for TAG 42 = 0x%x", fn, Recv_data[i]);
    return LSCSTATUS_FAILED;
  }
  i++;
  uint8_t tag42Len = Recv_data[i];
  // copy the data including length
  memcpy(gsTag42Arr, &Recv_data[i], tag42Len + 1);
  i = i + tag42Len + 1;
  ALOGD_IF(ese_debug_enabled, "%s: gsTag42Arr %s", fn, gsTag42Arr);
  if (Recv_data[i] != TAG_LSRE_SIGNID) {
    ALOGE("%s: Invalid Root entity for TAG 45 = 0x%x", fn, Recv_data[i]);
    return LSCSTATUS_FAILED;
  }
  uint8_t tag45Len = Recv_data[i + 1];
  memcpy(gsTag45Arr, &Recv_data[i + 1], tag45Len + 1);
  ALOGD_IF(ese_debug_enabled, "%s: Exiting", fn);
  return LSCSTATUS_SUCCESS;
}

LSCSTATUS Bufferize_load_cmds(__attribute__((unused)) Lsc_ImageInfo_t* Os_info,
                              __attribute__((unused)) LSCSTATUS status,
                              Lsc_TranscieveInfo_t* pTranscv_Info) {
  static const char fn[] = "Bufferize_load_cmds";

  if (gsCmd_count == 0x00) {
    if ((pTranscv_Info->sSendData[1] == INSTAL_LOAD_ID) &&
        (pTranscv_Info->sSendData[2] == PARAM_P1_OFFSET) &&
        (pTranscv_Info->sSendData[3] == 0x00)) {
      ALOGD_IF(ese_debug_enabled, "%s: BUffer: install for load", fn);
      gspBuffer[0] = pTranscv_Info->sSendlength;
      memcpy(&gspBuffer[1], &(pTranscv_Info->sSendData[0]),
             pTranscv_Info->sSendlength);
      gspBuffer = gspBuffer + pTranscv_Info->sSendlength + 1;
      gsCmd_count++;
      return LSCSTATUS_FAILED;
    }
    /* Do not buffer this cmd, Send to eSE */
    return LSCSTATUS_SUCCESS;
  } else {
    uint8_t Param_P2 = gsCmd_count - 1;
    if ((pTranscv_Info->sSendData[1] == LOAD_CMD_ID) &&
        (pTranscv_Info->sSendData[2] == LOAD_MORE_BLOCKS) &&
        (pTranscv_Info->sSendData[3] == Param_P2)) {
      ALOGD_IF(ese_debug_enabled, "%s: BUffer: load", fn);
      gspBuffer[0] = pTranscv_Info->sSendlength;
      memcpy(&gspBuffer[1], &(pTranscv_Info->sSendData[0]),
             pTranscv_Info->sSendlength);
      gspBuffer = gspBuffer + pTranscv_Info->sSendlength + 1;
      gsCmd_count++;
    } else if ((pTranscv_Info->sSendData[1] == LOAD_CMD_ID) &&
               (pTranscv_Info->sSendData[2] == LOAD_LAST_BLOCK) &&
               (pTranscv_Info->sSendData[3] == Param_P2)) {
      ALOGD_IF(ese_debug_enabled, "%s: BUffer: last load", fn);
      gsSendBack_cmds = true;
      gspBuffer[0] = pTranscv_Info->sSendlength;
      memcpy(&gspBuffer[1], &(pTranscv_Info->sSendData[0]),
             pTranscv_Info->sSendlength);
      gspBuffer = gspBuffer + pTranscv_Info->sSendlength + 1;
      gsCmd_count++;
      gsIslastcmdLoad = true;
    } else {
      ALOGD_IF(ese_debug_enabled, "%s: BUffer: Not a load cmd", fn);
      gsSendBack_cmds = true;
      gspBuffer[0] = pTranscv_Info->sSendlength;
      memcpy(&gspBuffer[1], &(pTranscv_Info->sSendData[0]),
             pTranscv_Info->sSendlength);
      gspBuffer = gspBuffer + pTranscv_Info->sSendlength + 1;
      gsIslastcmdLoad = false;
      gsCmd_count++;
    }
  }
  ALOGD_IF(ese_debug_enabled, "%s: exit", fn);
  return LSCSTATUS_FAILED;
}

LSCSTATUS Send_Backall_Loadcmds(Lsc_ImageInfo_t* Os_info, LSCSTATUS status,
                                Lsc_TranscieveInfo_t* pTranscv_Info) {
  static const char fn[] = "Send_Backall_Loadcmds";
  status = LSCSTATUS_FAILED;

  ALOGD_IF(ese_debug_enabled, "%s: enter", fn);
  gspBuffer = gsCmd_Buffer;  // Points to start of first cmd to send
  if (gsCmd_count == 0x00) {
    ALOGD_IF(ese_debug_enabled, "%s: No cmds stored to send to eSE", fn);
  } else {
    while (gsCmd_count-- > 0) {
      phNxpEse_data cmdApdu;
      phNxpEse_data rspApdu;
      phNxpEse_memset(&cmdApdu, 0x00, sizeof(phNxpEse_data));
      phNxpEse_memset(&rspApdu, 0x00, sizeof(phNxpEse_data));

      cmdApdu.len = (int32_t)(gspBuffer[0]);
      cmdApdu.p_data =
          (uint8_t*)phNxpEse_memalloc(cmdApdu.len * sizeof(uint8_t));
      gspBuffer = gspBuffer + 1 + cmdApdu.len;

      memcpy(cmdApdu.p_data, &gspBuffer[1], cmdApdu.len);

      ESESTATUS eseStat = phNxpEse_Transceive(&cmdApdu, &rspApdu);
      memcpy(pTranscv_Info->sRecvData, rspApdu.p_data, rspApdu.len);
      int32_t recvBufferActualSize = rspApdu.len;
      phNxpEse_free(cmdApdu.p_data);
      phNxpEse_free(rspApdu.p_data);

      if (eseStat != LSCSTATUS_SUCCESS || (recvBufferActualSize < 2)) {
        ALOGE("%s: Transceive failed; status=0x%X", fn, eseStat);
      } else if (gsCmd_count == 0x00) {
        // Last command in the buffer
        if (gsIslastcmdLoad == false) {
          status =
              Process_EseResponse(pTranscv_Info, recvBufferActualSize, Os_info);
        } else if ((recvBufferActualSize == 0x02) &&
                   (pTranscv_Info->sRecvData[recvBufferActualSize - 2] ==
                    0x90) &&
                   (pTranscv_Info->sRecvData[recvBufferActualSize - 1] ==
                    0x00)) {
          recvBufferActualSize = 0x03;
          pTranscv_Info->sRecvData[0] = 0x00;
          pTranscv_Info->sRecvData[1] = 0x90;
          pTranscv_Info->sRecvData[2] = 0x00;
          status =
              Process_EseResponse(pTranscv_Info, recvBufferActualSize, Os_info);
        } else {
          status =
              Process_EseResponse(pTranscv_Info, recvBufferActualSize, Os_info);
        }
      } else if ((recvBufferActualSize == 0x02) &&
                 (pTranscv_Info->sRecvData[0] == 0x90) &&
                 (pTranscv_Info->sRecvData[1] == 0x00)) {
        /*response ok without data, send next command in the buffer*/
      } else if ((recvBufferActualSize == 0x03) &&
                 (pTranscv_Info->sRecvData[0] == 0x00) &&
                 (pTranscv_Info->sRecvData[1] == 0x90) &&
                 (pTranscv_Info->sRecvData[2] == 0x00)) {
        /*response ok without data, send next command in the buffer*/
      } else if ((pTranscv_Info->sRecvData[recvBufferActualSize - 2] != 0x90) &&
                 (pTranscv_Info->sRecvData[recvBufferActualSize - 1] != 0x00)) {
        /*Error condition hence exiting the loop*/
        status =
            Process_EseResponse(pTranscv_Info, recvBufferActualSize, Os_info);
        /*If the sending of Load fails reset the count*/
        gsCmd_count = 0;
        break;
      }
    }
  }
  memset(gsCmd_Buffer, 0, sizeof(gsCmd_Buffer));
  gspBuffer = gsCmd_Buffer;  // point back to start of line
  gsCmd_count = 0x00;
  ALOGD_IF(ese_debug_enabled, "%s: exit: status=0x%x", fn, status);
  return status;
}
/*******************************************************************************
**
** Function:        Numof_lengthbytes
**
** Description:     Checks the number of length bytes and assigns
**                  length value to wLen.
**
** Returns:         Number of Length bytes
**
*******************************************************************************/
uint8_t Numof_lengthbytes(uint8_t* read_buf, int32_t* pLen) {
  static const char fn[] = "Numof_lengthbytes";
  uint8_t len_byte = 0;
  ALOGD_IF(ese_debug_enabled, "%s: enter", fn);

  if (read_buf[0] == 0x00) {
    ALOGE("%s: Invalid length zero", fn);
    len_byte = 0x00;
  } else if ((read_buf[0] & 0x80) == 0x80) {
    len_byte = read_buf[0] & 0x0F;
    len_byte = len_byte + 1;  // 1 byte added for byte 0x81
  } else {
    len_byte = 0x01;
  }

  /* To get the length of the value field */
  int32_t wLen = 0;
  switch (len_byte) {
    case 0:
      wLen = read_buf[0];
      break;
    case 1:
      /*1st byte is the length*/
      wLen = read_buf[0];
      break;
    case 2:
      /*2nd byte is the length*/
      wLen = read_buf[1];
      break;
    case 3:
      /*1st and 2nd bytes are length*/
      wLen = read_buf[1];
      wLen = ((wLen << 8) | (read_buf[2]));
      break;
    case 4:
      /*3bytes are the length*/
      wLen = read_buf[1];
      wLen = ((wLen << 16) | (read_buf[2] << 8));
      wLen = (wLen | (read_buf[3]));
      break;
    default:
      ALOGE("%s: Invalid length %d.", fn, len_byte);
      break;
  }

  *pLen = wLen;
  ALOGD_IF(ese_debug_enabled, "%s: exit; len_bytes=0x0%x, Length=%d", fn,
           len_byte, *pLen);
  return len_byte;
}

/*******************************************************************************
**
** Function:        Write_Response_To_OutFile
**
** Description:     Write the response to Out file
**                  with length recvlen from buffer RecvData.
**
** Returns:         Success if OK
**
*******************************************************************************/
LSCSTATUS Write_Response_To_OutFile(Lsc_ImageInfo_t* image_info,
                                    uint8_t* RecvData, int32_t recvlen,
                                    Ls_TagType tType) {
  static const char fn[] = "Write_Response_to_OutFile";

  ALOGD_IF(ese_debug_enabled, "%s: Enter", fn);
  /*If the Response out file is NULL or Other than LS commands*/
  if ((image_info->bytes_wrote == 0x55) || (tType == LS_Default)) {
    return LSCSTATUS_SUCCESS;
  }

  uint8_t tag43Len = 1;
  /*Certificate TAG occupies 2 bytes*/
  if (tType == LS_Cert) {
    tag43Len = 2;
  }

  /* |TAG|LEN|                      VAL                      |
   * |61 |XX |TAG|LEN|    VAL   |TAG|    LEN    |     VAL    |
   *         |43 |1/2|7F21/60/40|44 |apduRespLen|apduResponse|
   */
  int32_t tag44Len = 0;
  uint8_t ucTag44[3] = {0x00, 0x00, 0x00};
  int32_t tag61Len = 0;
  uint8_t tag43off = 0;
  uint8_t tag44off = 0;
  uint8_t tagLen = 0;
  uint8_t tagBuffer[12] = {0x61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  if (recvlen < 0x80) {
    tag44Len = 1;
    ucTag44[0] = recvlen;
    tag61Len = recvlen + 4 + tag43Len;

    if (tag61Len & 0x80) {
      tagBuffer[1] = 0x81;
      tagBuffer[2] = tag61Len;
      tag43off = 3;
      tag44off = 5 + tag43Len;
      tagLen = tag44off + 2;
    } else {
      tagBuffer[1] = tag61Len;
      tag43off = 2;
      tag44off = 4 + tag43Len;
      tagLen = tag44off + 2;
    }
  } else if ((recvlen >= 0x80) && (recvlen <= 0xFF)) {
    ucTag44[0] = 0x81;
    ucTag44[1] = recvlen;
    tag61Len = recvlen + 5 + tag43Len;
    tag44Len = 2;

    if ((tag61Len & 0xFF00) != 0) {
      tagBuffer[1] = 0x82;
      tagBuffer[2] = (tag61Len & 0xFF00) >> 8;
      tagBuffer[3] = (tag61Len & 0xFF);
      tag43off = 4;
      tag44off = 6 + tag43Len;
      tagLen = tag44off + 3;
    } else {
      tagBuffer[1] = 0x81;
      tagBuffer[2] = (tag61Len & 0xFF);
      tag43off = 3;
      tag44off = 5 + tag43Len;
      tagLen = tag44off + 3;
    }
  } else if ((recvlen > 0xFF) && (recvlen <= 0xFFFF)) {
    ucTag44[0] = 0x82;
    ucTag44[1] = (recvlen & 0xFF00) >> 8;
    ucTag44[2] = (recvlen & 0xFF);
    tag44Len = 3;

    tag61Len = recvlen + 6 + tag43Len;

    if ((tag61Len & 0xFF00) != 0) {
      tagBuffer[1] = 0x82;
      tagBuffer[2] = (tag61Len & 0xFF00) >> 8;
      tagBuffer[3] = (tag61Len & 0xFF);
      tag43off = 4;
      tag44off = 6 + tag43Len;
      tagLen = tag44off + 4;
    }
  }
  tagBuffer[tag43off] = 0x43;
  tagBuffer[tag43off + 1] = tag43Len;
  tagBuffer[tag44off] = 0x44;
  memcpy(&tagBuffer[tag44off + 1], &ucTag44[0], tag44Len);

  if (tType == LS_Cert) {
    tagBuffer[tag43off + 2] = 0x7F;
    tagBuffer[tag43off + 3] = 0x21;
  } else if (tType == LS_Sign) {
    tagBuffer[tag43off + 2] = 0x60;
  } else if (tType == LS_Comm) {
    tagBuffer[tag43off + 2] = 0x40;
  } else {
    /*Do nothing*/
  }

  uint8_t tempLen = 0;
  LSCSTATUS wStatus = LSCSTATUS_FAILED;
  int32_t status = 0;
  while (tempLen < tagLen) {
    status = fprintf(image_info->fResp, "%02X", tagBuffer[tempLen++]);
    if (status != 2) {
      ALOGE("%s: Invalid Response during fprintf; status=0x%x", fn, (status));
      wStatus = LSCSTATUS_FAILED;
      break;
    }
  }
  /*Updating the response data into out script*/
  int32_t respLen = 0;
  while (respLen < recvlen) {
    status = fprintf(image_info->fResp, "%02X", RecvData[respLen++]);
    if (status != 2) {
      ALOGE("%s: Invalid Response during fprintf; status=0x%x", fn, (status));
      wStatus = LSCSTATUS_FAILED;
      break;
    }
  }
  if (status == 2) {
    fprintf(image_info->fResp, "%s\n", "");
    ALOGD_IF(ese_debug_enabled,
             "%s: SUCCESS Response written to script out file", fn);
    wStatus = LSCSTATUS_SUCCESS;
  }
  fflush(image_info->fResp);
  return wStatus;
}

/*******************************************************************************
**
** Function:        Check_Certificate_Tag
**
** Description:     Check certificate Tag presence in script
**                  by 7F21 .
**
** Returns:         Success if Tag found
**
*******************************************************************************/
LSCSTATUS Check_Certificate_Tag(uint8_t* read_buf, uint16_t* offset1) {
  static const char fn[] = "Check_Certificate_Tag";
  uint16_t offset = *offset1;

  if (((read_buf[offset] << 8 | read_buf[offset + 1]) == TAG_CERTIFICATE)) {
    ALOGD_IF(ese_debug_enabled, "%s: TAGID: TAG_CERTIFICATE", fn);
    int32_t wLen;
    offset = offset + 2;
    uint16_t len_byte = Numof_lengthbytes(&read_buf[offset], &wLen);
    offset = offset + len_byte;
    *offset1 = offset;
    if (wLen <= MAX_CERT_LEN) return LSCSTATUS_SUCCESS;
  }
  return LSCSTATUS_FAILED;
}

/*******************************************************************************
**
** Function:        Check_SerialNo_Tag
**
** Description:     Check Serial number Tag presence in script
**                  by 0x93 .
**
** Returns:         Success if Tag found
**
*******************************************************************************/
LSCSTATUS Check_SerialNo_Tag(uint8_t* read_buf, uint16_t* offset1) {
  static const char fn[] = "Check_SerialNo_Tag";
  uint16_t offset = *offset1;

  if (read_buf[offset] == TAG_SERIAL_NO) {
    ALOGD_IF(ese_debug_enabled, "%s: TAGID: TAG_SERIAL_NO", fn);
    uint8_t serNoLen = read_buf[offset + 1];
    offset = offset + serNoLen + 2;
    *offset1 = offset;
    ALOGD_IF(ese_debug_enabled, "%s: TAG_LSROOT_ENTITY is %x", fn,
             read_buf[offset]);
    return LSCSTATUS_SUCCESS;
  }
  return LSCSTATUS_FAILED;
}

/*******************************************************************************
**
** Function:        Check_LSRootID_Tag
**
** Description:     Check LS root ID tag presence in script and compare with
**                  select response root ID value.
**
** Returns:         Success if Tag found
**
*******************************************************************************/
LSCSTATUS Check_LSRootID_Tag(uint8_t* read_buf, uint16_t* offset1) {
  static const char fn[] = "Check_LSRootID_Tag";
  uint16_t offset = *offset1;

  if (read_buf[offset] == TAG_LSRE_ID) {
    ALOGD_IF(ese_debug_enabled, "%s: TAGID: TAG_LSROOT_ENTITY", fn);
    if (gsTag42Arr[0] == read_buf[offset + 1]) {
      uint8_t tag42Len = read_buf[offset + 1];
      offset = offset + 2;
      if (!memcmp(&read_buf[offset], &gsTag42Arr[1], gsTag42Arr[0])) {
        ALOGD_IF(ese_debug_enabled, "%s : TAG 42 verified", fn);
        offset = offset + tag42Len;
        *offset1 = offset;
        return LSCSTATUS_SUCCESS;
      }
    }
  }
  return LSCSTATUS_FAILED;
}

/*******************************************************************************
**
** Function:        Check_CertHoldID_Tag
**
** Description:     Check certificate holder ID tag presence in script.
**
** Returns:         Success if Tag found
**
*******************************************************************************/
LSCSTATUS Check_CertHoldID_Tag(uint8_t* read_buf, uint16_t* offset1) {
  static const char fn[] = "Check_CertHoldID_Tag";
  uint16_t offset = *offset1;

  if ((read_buf[offset] << 8 | read_buf[offset + 1]) == TAG_CERTFHOLD_ID) {
    uint8_t certfHoldIDLen = 0;
    ALOGD_IF(ese_debug_enabled, "%s: TAGID: TAG_CERTFHOLD_ID", fn);
    certfHoldIDLen = read_buf[offset + 2];
    offset = offset + certfHoldIDLen + 3;
    if (read_buf[offset] == TAG_KEY_USAGE) {
      ALOGD_IF(ese_debug_enabled, "%s: TAGID: TAG_KEY_USAGE", fn);
      uint8_t keyusgLen = read_buf[offset + 1];
      offset = offset + keyusgLen + 2;
      *offset1 = offset;
      return LSCSTATUS_SUCCESS;
    }
  }
  return LSCSTATUS_FAILED;
}

/*******************************************************************************
**
** Function:        Check_Date_Tag
**
** Description:     Check date tags presence in script.
**
** Returns:         Success if Tag found
**
*******************************************************************************/
LSCSTATUS Check_Date_Tag(uint8_t* read_buf, uint16_t* offset1) {
  static const char fn[] = "Check_Date_Tag";
  LSCSTATUS status = LSCSTATUS_FAILED;
  uint16_t offset = *offset1;

  if ((read_buf[offset] << 8 | read_buf[offset + 1]) == TAG_EFF_DATE) {
    uint8_t effDateLen = read_buf[offset + 2];
    offset = offset + 3 + effDateLen;
    ALOGD_IF(ese_debug_enabled, "%s: TAGID: TAG_EFF_DATE", fn);
    if ((read_buf[offset] << 8 | read_buf[offset + 1]) == TAG_EXP_DATE) {
      uint8_t effExpLen = read_buf[offset + 2];
      offset = offset + 3 + effExpLen;
      ALOGD_IF(ese_debug_enabled, "%s: TAGID: TAG_EXP_DATE", fn);
      status = LSCSTATUS_SUCCESS;
    } else if (read_buf[offset] == TAG_LSRE_SIGNID) {
      status = LSCSTATUS_SUCCESS;
    }
  } else if ((read_buf[offset] << 8 | read_buf[offset + 1]) == TAG_EXP_DATE) {
    uint8_t effExpLen = read_buf[offset + 2];
    offset = offset + 3 + effExpLen;
    ALOGD_IF(ese_debug_enabled, "%s: TAGID: TAG_EXP_DATE", fn);
    status = LSCSTATUS_SUCCESS;
  } else if (read_buf[offset] == TAG_LSRE_SIGNID) {
    status = LSCSTATUS_SUCCESS;
  } else {
    /*LSCSTATUS_FAILED*/
  }
  *offset1 = offset;
  return status;
}

/*******************************************************************************
**
** Function:        Check_45_Tag
**
** Description:     Check 45 tags presence in script and compare the value
**                  with select response tag 45 value
**
** Returns:         Success if Tag found
**
*******************************************************************************/
LSCSTATUS Check_45_Tag(uint8_t* read_buf, uint16_t* offset1,
                       uint8_t* tag45Len) {
  static const char fn[] = "Check_45_Tag";
  uint16_t offset = *offset1;
  if (read_buf[offset] == TAG_LSRE_SIGNID) {
    *tag45Len = read_buf[offset + 1];
    offset = offset + 2;
    if (gsTag45Arr[0] == *tag45Len) {
      if (!memcmp(&read_buf[offset], &gsTag45Arr[1], gsTag45Arr[0])) {
        *offset1 = offset;
        ALOGD_IF(ese_debug_enabled,
                 "%s: LSC_Check_KeyIdentifier : TAG 45 verified", fn);
        return LSCSTATUS_SUCCESS;
      }
    }
  }
  return LSCSTATUS_FAILED;
}

/*******************************************************************************
**
** Function:        Certificate_Verification
**
** Description:     Perform the certificate verification by forwarding it to
**                  LS applet.
**
** Returns:         Success if certificate is verified
**
*******************************************************************************/
LSCSTATUS Certificate_Verification(Lsc_ImageInfo_t* Os_info,
                                   Lsc_TranscieveInfo_t* pTranscv_Info,
                                   uint8_t* read_buf, uint16_t* offset1,
                                   uint8_t* tag45Len) {
  static const char fn[] = "Certificate_Verification";

  pTranscv_Info->sSendData[0] = 0x80;
  pTranscv_Info->sSendData[1] = 0xA0;
  pTranscv_Info->sSendData[2] = 0x01;
  pTranscv_Info->sSendData[3] = 0x00;

  int32_t wCertfLen = (read_buf[2] << 8 | read_buf[3]);
  uint16_t offset = *offset1;
  /*If the certificate is less than 255 bytes*/
  if (wCertfLen <= 251) {
    uint8_t tag7f49Off = 0;
    uint8_t u7f49Len = 0;
    uint8_t tag5f37Len = 0;
    ALOGD_IF(ese_debug_enabled, "%s: Certificate is less than 255", fn);
    offset = offset + *tag45Len;
    ALOGD_IF(ese_debug_enabled, "%s: Before TAG_CCM_PERMISSION = %x", fn,
             read_buf[offset]);
    if (read_buf[offset] != TAG_CCM_PERMISSION) {
      return LSCSTATUS_FAILED;
    }
    int32_t tag53Len = 0;
    uint8_t len_byte = 0;
    offset = offset + 1;
    len_byte = Numof_lengthbytes(&read_buf[offset], &tag53Len);
    offset = offset + tag53Len + len_byte;
    ALOGD_IF(ese_debug_enabled, "%s: Verified TAG TAG_CCM_PERMISSION = 0x53",
             fn);
    if ((uint16_t)(read_buf[offset] << 8 | read_buf[offset + 1]) !=
        TAG_SIG_RNS_COMP) {
      return LSCSTATUS_FAILED;
    }
    tag7f49Off = offset;
    u7f49Len = read_buf[offset + 2];
    offset = offset + 3 + u7f49Len;
    if (u7f49Len != 64) {
      return LSCSTATUS_FAILED;
    }
    if ((uint16_t)(read_buf[offset] << 8 | read_buf[offset + 1]) != 0x7f49) {
      return LSCSTATUS_FAILED;
    }
    tag5f37Len = read_buf[offset + 2];
    if (read_buf[offset + 3] != 0x86 || (read_buf[offset + 4] != 65)) {
      return LSCSTATUS_FAILED;
    }
    uint8_t tag_len_byte = Numof_lengthbytes(&read_buf[2], &wCertfLen);
    pTranscv_Info->sSendData[4] = wCertfLen + 2 + tag_len_byte;
    pTranscv_Info->sSendlength = wCertfLen + 7 + tag_len_byte;
    memcpy(&(pTranscv_Info->sSendData[5]), &read_buf[0],
           wCertfLen + 2 + tag_len_byte);

    ALOGD_IF(ese_debug_enabled, "%s: start transceive for length %d", fn,
             pTranscv_Info->sSendlength);
    LSCSTATUS status = LSCSTATUS_FAILED;
    status = LSC_SendtoLsc(Os_info, status, pTranscv_Info, LS_Cert);
    if (status == LSCSTATUS_SUCCESS) {
      ALOGD_IF(ese_debug_enabled, "%s: Certificate is verified", fn);
    }
    return status;
  } else {
    /*If the certificate is more than 255 bytes*/
    uint8_t tag7f49Off = 0;
    uint8_t u7f49Len = 0;
    uint8_t tag5f37Len = 0;
    ALOGD_IF(ese_debug_enabled, "%s: Certificate is greater than 255", fn);
    offset = offset + *tag45Len;
    ALOGD_IF(ese_debug_enabled, "%s: Before TAG_CCM_PERMISSION = %x", fn,
             read_buf[offset]);
    if (read_buf[offset] != TAG_CCM_PERMISSION) {
      return LSCSTATUS_FAILED;
    }
    int32_t tag53Len = 0;
    uint8_t len_byte = 0;
    offset = offset + 1;
    len_byte = Numof_lengthbytes(&read_buf[offset], &tag53Len);
    offset = offset + tag53Len + len_byte;
    ALOGD_IF(ese_debug_enabled, "%s: Verified TAG TAG_CCM_PERMISSION = 0x53",
             fn);
    if ((uint16_t)(read_buf[offset] << 8 | read_buf[offset + 1]) !=
        TAG_SIG_RNS_COMP) {
      return LSCSTATUS_FAILED;
    }
    tag7f49Off = offset;
    u7f49Len = read_buf[offset + 2];
    offset = offset + 3 + u7f49Len;
    if (u7f49Len != 64) {
      return LSCSTATUS_FAILED;
    }
    if ((uint16_t)(read_buf[offset] << 8 | read_buf[offset + 1]) != 0x7f49) {
      return LSCSTATUS_FAILED;
    }
    tag5f37Len = read_buf[offset + 2];
    if (read_buf[offset + 3] != 0x86 || (read_buf[offset + 4] != 65)) {
      return LSCSTATUS_FAILED;
    }
    pTranscv_Info->sSendData[4] = tag7f49Off;
    memcpy(&(pTranscv_Info->sSendData[5]), &read_buf[0], tag7f49Off);
    pTranscv_Info->sSendlength = tag7f49Off + 5;
    ALOGD_IF(ese_debug_enabled, "%s: start transceive for length %d", fn,
             pTranscv_Info->sSendlength);

    LSCSTATUS status = LSCSTATUS_FAILED;
    status = LSC_SendtoLsc(Os_info, status, pTranscv_Info, LS_Default);
    if (status != LSCSTATUS_SUCCESS) {
      uint8_t* RecvData = pTranscv_Info->sRecvData;
      Write_Response_To_OutFile(Os_info, RecvData, gsResp_len, LS_Cert);
      return status;
    }

    pTranscv_Info->sSendData[2] = 0x00;
    pTranscv_Info->sSendData[4] = u7f49Len + tag5f37Len + 6;
    memcpy(&(pTranscv_Info->sSendData[5]), &read_buf[tag7f49Off],
           u7f49Len + tag5f37Len + 6);
    pTranscv_Info->sSendlength = u7f49Len + tag5f37Len + 11;
    ALOGD_IF(ese_debug_enabled, "%s: start transceive for length %d", fn,
             pTranscv_Info->sSendlength);

    status = LSC_SendtoLsc(Os_info, status, pTranscv_Info, LS_Cert);
    if (status == LSCSTATUS_SUCCESS) {
      ALOGD_IF(ese_debug_enabled, "Certificate is verified");
    }
    return status;
  }
  return LSCSTATUS_FAILED;
}

/*******************************************************************************
**
** Function:        Check_Complete_7F21_Tag
**
** Description:     Traverses the 7F21 tag for verification of each sub tag with
**                  in the 7F21 tag.
**
** Returns:         Success if all tags are verified
**
*******************************************************************************/
LSCSTATUS Check_Complete_7F21_Tag(Lsc_ImageInfo_t* Os_info,
                                  Lsc_TranscieveInfo_t* pTranscv_Info,
                                  uint8_t* read_buf, uint16_t* offset) {
  static const char fn[] = "Check_Complete_7F21_Tag";

  if (LSCSTATUS_SUCCESS != Check_Certificate_Tag(read_buf, offset)) {
    ALOGE("%s: FAILED in Check_Certificate_Tag", fn);
    return LSCSTATUS_FAILED;
  }
  if (LSCSTATUS_SUCCESS != Check_SerialNo_Tag(read_buf, offset)) {
    ALOGE("%s: FAILED in Check_SerialNo_Tag", fn);
    return LSCSTATUS_FAILED;
  }
  if (LSCSTATUS_SUCCESS != Check_LSRootID_Tag(read_buf, offset)) {
    ALOGE("%s: FAILED in Check_LSRootID_Tag", fn);
    return LSCSTATUS_FAILED;
  }
  if (LSCSTATUS_SUCCESS != Check_CertHoldID_Tag(read_buf, offset)) {
    ALOGE("%s: FAILED in Check_CertHoldID_Tag", fn);
    return LSCSTATUS_FAILED;
  }
  if (LSCSTATUS_SUCCESS != Check_Date_Tag(read_buf, offset)) {
    ALOGE("%s: FAILED in Check_CertHoldID_Tag", fn);
    return LSCSTATUS_FAILED;
  }
  uint8_t tag45Len = 0;
  if (LSCSTATUS_SUCCESS != Check_45_Tag(read_buf, offset, &tag45Len)) {
    ALOGE("%s: FAILED in Check_CertHoldID_Tag", fn);
    return LSCSTATUS_FAILED;
  }
  if (LSCSTATUS_SUCCESS != Certificate_Verification(Os_info, pTranscv_Info,
                                                    read_buf, offset,
                                                    &tag45Len)) {
    ALOGE("%s: FAILED in Certificate_Verification", fn);
    return LSCSTATUS_FAILED;
  }
  return LSCSTATUS_SUCCESS;
}

/*******************************************************************************
**
** Function:        LSC_UpdateExeStatus
**
** Description:     Updates LSC status to a file
**
** Returns:         true if success else false
**
*******************************************************************************/
bool LSC_UpdateExeStatus(uint16_t status) {
  static const char fn[] = "LSC_UpdateExeStatus";

  ALOGD_IF(ese_debug_enabled, "%s: enter", fn);

  FILE* fLsStatus = fopen(LS_STATUS_PATH, "w+");
  if (fLsStatus == NULL) {
    ALOGE("%s: Error opening LS Status file for backup: %s", fn,
          strerror(errno));
    return false;
  }
  if ((fprintf(fLsStatus, "%04x", status)) != 4) {
    ALOGE("%s: Error updating LS Status backup: %s", fn, strerror(errno));
    fclose(fLsStatus);
    return false;
  }
  fclose(fLsStatus);
  ALOGD_IF(ese_debug_enabled, "%s: exit", fn);
  return true;
}

/*******************************************************************************
**
** Function:        Get_LsStatus
**
** Description:     Interface to fetch Loader service client status to JNI,
**                  Services
**
** Returns:         SUCCESS/FAILURE
**
*******************************************************************************/
LSCSTATUS Get_LsStatus(uint8_t* pStatus) {
  static const char fn[] = "Get_LsStatus";

  FILE* fLsStatus = fopen(LS_STATUS_PATH, "r");
  if (fLsStatus == NULL) {
    ALOGE("%s: Error opening LS Status file for backup: %s", fn,
          strerror(errno));
    return LSCSTATUS_FAILED;
  }

  uint8_t lsStatus[2] = {0x63, 0x40};
  for (uint8_t loopcnt = 0; loopcnt < 2; loopcnt++) {
    if ((FSCANF_BYTE(fLsStatus, "%2x", &lsStatus[loopcnt])) == 0) {
      ALOGE("%s: Error updating LS Status backup: %s", fn, strerror(errno));
      fclose(fLsStatus);
      return LSCSTATUS_FAILED;
    }
  }
  ALOGD_IF(ese_debug_enabled, "%s: LS Status 0x%X 0x%X", fn, lsStatus[0],
           lsStatus[1]);
  memcpy(pStatus, lsStatus, 2);
  fclose(fLsStatus);
  return LSCSTATUS_SUCCESS;
}