blob: 57bbf9776d91645df023dc0271927cb4a084d9bb [file] [log] [blame]
/******************************************************************************
*
* 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 <cutils/properties.h>
#include <dirent.h>
#include <log/log.h>
#include <openssl/evp.h>
#include <pthread.h>
#include <stdlib.h>
#include <string>
#include "LsLib.h"
uint8_t datahex(char c);
unsigned char* getHASH(uint8_t* buffer, size_t buffSize);
extern bool ese_debug_enabled;
#define ls_script_source_prefix "/vendor/etc/loaderservice_updater_"
#define ls_script_source_suffix ".lss"
#define ls_script_output_prefix \
"/data/vendor/secure_element/loaderservice_updater_out_"
#define ls_script_output_suffix ".txt"
const size_t HASH_DATA_LENGTH = 21;
const uint16_t HASH_STATUS_INDEX = 20;
const uint8_t LS_MAX_COUNT = 10;
const uint8_t LS_DOWNLOAD_SUCCESS = 0x00;
const uint8_t LS_DOWNLOAD_FAILED = 0x01;
static android::sp<ISecureElementHalCallback> cCallback;
void* performLSDownload_thread(void* data);
static void getLSScriptSourcePrefix(std::string& prefix);
void getLSScriptSourcePrefix(std::string& prefix) {
char source_path[PROPERTY_VALUE_MAX] = {0};
int len = property_get("vendor.ese.loader_script_path", source_path, "");
if (len > 0) {
FILE* fd = fopen(source_path, "rb");
if (fd != NULL) {
char c;
while (!feof(fd) && fread(&c, 1, 1, fd) == 1) {
if (c == ' ' || c == '\n' || c == '\r' || c == 0x00) break;
prefix.push_back(c);
}
} else {
ALOGD("%s Cannot open file %s\n", __func__, source_path);
}
}
if (prefix.empty()) {
prefix.assign(ls_script_source_prefix);
}
}
/*******************************************************************************
**
** Function: LSC_Start
**
** Description: Starts the LSC update with encrypted data privided in the
updater file
**
** Returns: SUCCESS if ok.
**
*******************************************************************************/
LSCSTATUS LSC_Start(const char* name, const char* dest, uint8_t* pdata,
uint16_t len, uint8_t* respSW) {
static const char fn[] = "LSC_Start";
LSCSTATUS status = LSCSTATUS_FAILED;
if (name != NULL) {
status = Perform_LSC(name, dest, pdata, len, respSW);
} else {
ALOGE("%s: LS script file is missing", fn);
}
ALOGD_IF(ese_debug_enabled, "%s: Exit; status=0x0%X", fn, status);
return status;
}
/*******************************************************************************
**
** Function: LSC_doDownload
**
** Description: Start LS download process by creating thread
**
** Returns: SUCCESS of ok
**
*******************************************************************************/
LSCSTATUS LSC_doDownload(
const android::sp<ISecureElementHalCallback>& clientCallback) {
static const char fn[] = "LSC_doDownload";
LSCSTATUS status;
pthread_t thread;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
cCallback = clientCallback;
if (pthread_create(&thread, &attr, &performLSDownload_thread, NULL) < 0) {
ALOGE("%s: Thread creation failed", fn);
status = LSCSTATUS_FAILED;
} else {
status = LSCSTATUS_SUCCESS;
}
pthread_attr_destroy(&attr);
return status;
}
/*******************************************************************************
**
** Function: performLSDownload_thread
**
** Description: Perform LS during hal init
**
** Returns: None
**
*******************************************************************************/
void* performLSDownload_thread(__attribute__((unused)) void* data) {
ALOGD_IF(ese_debug_enabled, "%s enter ", __func__);
/*generated SHA-1 string for secureElementLS
This will remain constant as handled in secureElement HAL*/
char sha1[] = "6d583e84f2710e6b0f06beebc1a12a1083591373";
uint8_t hash[20] = {0};
for (int i = 0; i < 40; i = i + 2) {
hash[i / 2] =
(((datahex(sha1[i]) & 0x0F) << 4) | (datahex(sha1[i + 1]) & 0x0F));
}
uint8_t resSW[4] = {0x4e, 0x02, 0x69, 0x87};
std::string sourcePath;
std::string sourcePrefix;
std::string outPath;
int index = 1;
LSCSTATUS status = LSCSTATUS_SUCCESS;
Lsc_HashInfo_t lsHashInfo;
getLSScriptSourcePrefix(sourcePrefix);
do {
/*Open the script file from specified location and name*/
sourcePath.assign(sourcePrefix);
sourcePath += ('0' + index);
sourcePath += ls_script_source_suffix;
FILE* fIn = fopen(sourcePath.c_str(), "rb");
if (fIn == NULL) {
ALOGE("%s Cannot open LS script file %s\n", __func__, sourcePath.c_str());
ALOGE("%s Error : %s", __func__, strerror(errno));
break;
}
ALOGD_IF(ese_debug_enabled, "%s File opened %s\n", __func__,
sourcePath.c_str());
outPath.assign(ls_script_output_prefix);
outPath += ('0' + index);
outPath += ls_script_output_suffix;
FILE* fOut = fopen(outPath.c_str(), "wb+");
if (fOut == NULL) {
ALOGE("%s Failed to open file %s\n", __func__, outPath.c_str());
break;
}
/*Read the script content to a local buffer*/
fseek(fIn, 0, SEEK_END);
long lsBufSize = ftell(fIn);
rewind(fIn);
if (lsHashInfo.lsRawScriptBuf == nullptr) {
lsHashInfo.lsRawScriptBuf = (uint8_t*)phNxpEse_memalloc(lsBufSize + 1);
}
memset(lsHashInfo.lsRawScriptBuf, 0x00, (lsBufSize + 1));
fread(lsHashInfo.lsRawScriptBuf, lsBufSize, 1, fIn);
LSCSTATUS lsHashStatus = LSCSTATUS_FAILED;
/*Get 20bye SHA1 of the script*/
lsHashInfo.lsScriptHash =
getHASH(lsHashInfo.lsRawScriptBuf, (size_t)lsBufSize);
phNxpEse_free(lsHashInfo.lsRawScriptBuf);
lsHashInfo.lsRawScriptBuf = nullptr;
if (lsHashInfo.lsScriptHash == nullptr) break;
if (lsHashInfo.readBuffHash == nullptr) {
lsHashInfo.readBuffHash = (uint8_t*)phNxpEse_memalloc(HASH_DATA_LENGTH);
}
memset(lsHashInfo.readBuffHash, 0x00, HASH_DATA_LENGTH);
/*Read the hash from applet for specified slot*/
lsHashStatus =
LSC_ReadLsHash(lsHashInfo.readBuffHash, &lsHashInfo.readHashLen, index);
/*Check if previously script is successfully installed.
if yes, continue reading next script else try update wit current script*/
if ((lsHashStatus == LSCSTATUS_SUCCESS) &&
(lsHashInfo.readHashLen == HASH_DATA_LENGTH) &&
(0 == memcmp(lsHashInfo.lsScriptHash, lsHashInfo.readBuffHash,
HASH_DATA_LENGTH)) &&
(lsHashInfo.readBuffHash[HASH_STATUS_INDEX] == LS_DOWNLOAD_SUCCESS)) {
ALOGD_IF(ese_debug_enabled, "%s LS Loader sript is already installed \n",
__func__);
continue;
}
/*Uptdates current script*/
status = LSC_Start(sourcePath.c_str(), outPath.c_str(), (uint8_t*)hash,
(uint16_t)sizeof(hash), resSW);
ALOGD_IF(ese_debug_enabled, "%s script %s perform done, result = %d\n",
__func__, sourcePath.c_str(), status);
if (status != LSCSTATUS_SUCCESS) {
lsHashInfo.lsScriptHash[HASH_STATUS_INDEX] = LS_DOWNLOAD_FAILED;
/*If current script updation fails, update the status with hash to the
* applet then clean and exit*/
lsHashStatus =
LSC_UpdateLsHash(lsHashInfo.lsScriptHash, HASH_DATA_LENGTH, index);
if (lsHashStatus != LSCSTATUS_SUCCESS) {
ALOGD_IF(ese_debug_enabled, "%s LSC_UpdateLsHash Failed\n", __func__);
}
ESESTATUS estatus = phNxpEse_deInit();
if (estatus == ESESTATUS_SUCCESS) {
estatus = phNxpEse_close();
if (estatus == ESESTATUS_SUCCESS) {
ALOGD_IF(ese_debug_enabled, "%s: Ese_close success\n", __func__);
}
} else {
ALOGE("%s: Ese_deInit failed", __func__);
}
cCallback->onStateChange(false);
break;
} else {
/*If current script execution is succes, update the status along with the
* hash to the applet*/
lsHashInfo.lsScriptHash[HASH_STATUS_INDEX] = LS_DOWNLOAD_SUCCESS;
lsHashStatus =
LSC_UpdateLsHash(lsHashInfo.lsScriptHash, HASH_DATA_LENGTH, index);
if (lsHashStatus != LSCSTATUS_SUCCESS) {
ALOGD_IF(ese_debug_enabled, "%s LSC_UpdateLsHash Failed\n", __func__);
}
}
} while (++index <= LS_MAX_COUNT);
phNxpEse_free(lsHashInfo.readBuffHash);
if (status == LSCSTATUS_SUCCESS) {
cCallback->onStateChange(true);
}
pthread_exit(NULL);
ALOGD_IF(ese_debug_enabled, "%s pthread_exit\n", __func__);
return NULL;
}
/*******************************************************************************
**
** Function: getHASH
**
** Description: generates SHA1 of given buffer
**
** Returns: 20 bytes of SHA1
**
*******************************************************************************/
unsigned char* getHASH(uint8_t* buffer, size_t buffSize) {
static uint8_t outHash[HASH_DATA_LENGTH] = {0};
unsigned int md_len = -1;
const EVP_MD* md = EVP_get_digestbyname("SHA1");
if (NULL != md) {
EVP_MD_CTX mdctx;
EVP_MD_CTX_init(&mdctx);
EVP_DigestInit_ex(&mdctx, md, NULL);
EVP_DigestUpdate(&mdctx, buffer, buffSize);
EVP_DigestFinal_ex(&mdctx, outHash, &md_len);
EVP_MD_CTX_cleanup(&mdctx);
}
return outHash;
}
/*******************************************************************************
**
** Function: datahex
**
** Description: Converts char to uint8_t
**
** Returns: uint8_t variable
**
*******************************************************************************/
uint8_t datahex(char c) {
uint8_t value = 0;
if (c >= '0' && c <= '9')
value = (c - '0');
else if (c >= 'A' && c <= 'F')
value = (10 + (c - 'A'));
else if (c >= 'a' && c <= 'f')
value = (10 + (c - 'a'));
return value;
}