/****************************************************************************** * * Copyright (C) 2018 ST Microelectronics S.A. * * 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 "StEse-SecureElement" #include "SecureElement.h" #include #include #include #include #include #define VENDOR_LIB_PATH "/vendor/lib64/" #define VENDOR_LIB_EXT ".so" typedef int (*STEseReset)(void); extern bool ese_debug_enabled; static bool OpenLogicalChannelProcessing = false; static bool OpenBasicChannelProcessing = false; namespace android { namespace hardware { namespace secure_element { namespace V1_2 { namespace implementation { sp SecureElement::mCallbackV1_1 = nullptr; sp SecureElement::mCallbackV1_0 = nullptr; SecureElement::SecureElement() : mOpenedchannelCount(0), mOpenedChannels{false, false, false, false} {} Return SecureElement::init( const sp< ::android::hardware::secure_element::V1_0::ISecureElementHalCallback>& clientCallback) { ESESTATUS status = ESESTATUS_SUCCESS; STLOG_HAL_D("%s: Enter", __func__); if (clientCallback == nullptr) { return Void(); } else { mCallbackV1_0 = clientCallback; mCallbackV1_1 = nullptr; if (!mCallbackV1_0->linkToDeath(this, 0 /*cookie*/)) { STLOG_HAL_E("%s: Failed to register death notification", __func__); } } if (isSeInitialized()) { clientCallback->onStateChange(true); return Void(); } status = seHalInit(); if (status != ESESTATUS_SUCCESS) { clientCallback->onStateChange(false); return Void(); } else { clientCallback->onStateChange(true); return Void(); } } Return SecureElement::init_1_1( const sp< ::android::hardware::secure_element::V1_1::ISecureElementHalCallback>& clientCallback) { ESESTATUS status = ESESTATUS_SUCCESS; STLOG_HAL_D("%s: Enter", __func__); if (clientCallback == nullptr) { return Void(); } else { mCallbackV1_1 = clientCallback; mCallbackV1_0 = nullptr; if (!mCallbackV1_1->linkToDeath(this, 0 /*cookie*/)) { STLOG_HAL_E("%s: Failed to register death notification", __func__); } } if (isSeInitialized()) { clientCallback->onStateChange_1_1(true, "SE already initialized"); return Void(); } status = seHalInit(); if (status != ESESTATUS_SUCCESS) { clientCallback->onStateChange_1_1(false, "SE initialization failed"); return Void(); } else { clientCallback->onStateChange_1_1(true, "SE initialized"); return Void(); } } Return SecureElement::getAtr(getAtr_cb _hidl_cb) { STLOG_HAL_D("%s: Enter", __func__); hidl_vec response; uint8_t* ATR; ATR = StEse_getAtr(); if (ATR != nullptr) { uint8_t len = *ATR; if (len) { response.resize(len); memcpy(&response[0], ATR, len); } } _hidl_cb(response); return Void(); } Return SecureElement::isCardPresent() { return true; } Return SecureElement::transmit(const hidl_vec& data, transmit_cb _hidl_cb) { ESESTATUS status = ESESTATUS_FAILED; StEse_data cmdApdu; StEse_data rspApdu; memset(&cmdApdu, 0x00, sizeof(StEse_data)); memset(&rspApdu, 0x00, sizeof(StEse_data)); STLOG_HAL_D("%s: Enter", __func__); cmdApdu.len = data.size(); if (cmdApdu.len >= MIN_APDU_LENGTH) { cmdApdu.p_data = (uint8_t*)malloc(data.size() * sizeof(uint8_t)); memcpy(cmdApdu.p_data, data.data(), cmdApdu.len); status = StEse_Transceive(&cmdApdu, &rspApdu); } hidl_vec result; if (status != ESESTATUS_SUCCESS) { STLOG_HAL_E("%s: transmit failed!!!", __func__); seHalResetSe(); } else { result.resize(rspApdu.len); memcpy(&result[0], rspApdu.p_data, rspApdu.len); } _hidl_cb(result); free(cmdApdu.p_data); free(rspApdu.p_data); return Void(); } Return SecureElement::openLogicalChannel(const hidl_vec& aid, uint8_t p2, openLogicalChannel_cb _hidl_cb) { hidl_vec manageChannelCommand = {0x00, 0x70, 0x00, 0x00, 0x01}; OpenLogicalChannelProcessing = true; LogicalChannelResponse resApduBuff; resApduBuff.channelNumber = 0xff; memset(&resApduBuff, 0x00, sizeof(resApduBuff)); STLOG_HAL_D("%s: Enter", __func__); if (!isSeInitialized()) { STLOG_HAL_D("%s: Enter SeInitialized", __func__); ESESTATUS status = seHalInit(); if (status != ESESTATUS_SUCCESS) { STLOG_HAL_E("%s: seHalInit Failed!!!", __func__); _hidl_cb(resApduBuff, SecureElementStatus::IOERROR); OpenLogicalChannelProcessing = false; return Void(); } } SecureElementStatus sestatus = SecureElementStatus::IOERROR; ESESTATUS status = ESESTATUS_FAILED; StEse_data cmdApdu; StEse_data rspApdu; memset(&cmdApdu, 0x00, sizeof(StEse_data)); memset(&rspApdu, 0x00, sizeof(StEse_data)); cmdApdu.len = manageChannelCommand.size(); cmdApdu.p_data = (uint8_t*)malloc(manageChannelCommand.size() * sizeof(uint8_t)); if (cmdApdu.p_data != NULL) { memcpy(cmdApdu.p_data, manageChannelCommand.data(), cmdApdu.len); status = StEse_Transceive(&cmdApdu, &rspApdu); } if (status != ESESTATUS_SUCCESS) { /*Transceive failed*/ sestatus = SecureElementStatus::IOERROR; } else if (rspApdu.p_data[rspApdu.len - 2] == 0x90 && rspApdu.p_data[rspApdu.len - 1] == 0x00) { /*ManageChannel successful*/ resApduBuff.channelNumber = rspApdu.p_data[0]; mOpenedchannelCount++; mOpenedChannels[resApduBuff.channelNumber] = true; sestatus = SecureElementStatus::SUCCESS; } else if (rspApdu.p_data[rspApdu.len - 2] == 0x6A && rspApdu.p_data[rspApdu.len - 1] == 0x81) { sestatus = SecureElementStatus::CHANNEL_NOT_AVAILABLE; } else if (((rspApdu.p_data[rspApdu.len - 2] == 0x6E) || (rspApdu.p_data[rspApdu.len - 2] == 0x6D)) && rspApdu.p_data[rspApdu.len - 1] == 0x00) { sestatus = SecureElementStatus::UNSUPPORTED_OPERATION; } /*Free the allocations*/ free(cmdApdu.p_data); cmdApdu.p_data = NULL; free(rspApdu.p_data); rspApdu.p_data = NULL; if (sestatus != SecureElementStatus::SUCCESS) { /* if the SE is unresponsive, reset it */ if (sestatus == SecureElementStatus::IOERROR) { seHalResetSe(); } /*If manageChannel is failed in any of above cases send the callback and return*/ _hidl_cb(resApduBuff, sestatus); STLOG_HAL_E("%s: Exit - manage channel failed!!", __func__); OpenLogicalChannelProcessing = false; return Void(); } STLOG_HAL_D("%s: Sending selectApdu", __func__); /*Reset variables if manageChannel is success*/ sestatus = SecureElementStatus::IOERROR; status = ESESTATUS_FAILED; memset(&cmdApdu, 0x00, sizeof(StEse_data)); memset(&rspApdu, 0x00, sizeof(StEse_data)); cmdApdu.len = (int32_t)(6 + aid.size()); cmdApdu.p_data = (uint8_t*)malloc(cmdApdu.len * sizeof(uint8_t)); if (cmdApdu.p_data != NULL) { uint8_t xx = 0; cmdApdu.p_data[xx++] = resApduBuff.channelNumber; cmdApdu.p_data[xx++] = 0xA4; // INS cmdApdu.p_data[xx++] = 0x04; // P1 cmdApdu.p_data[xx++] = p2; // P2 cmdApdu.p_data[xx++] = aid.size(); // Lc memcpy(&cmdApdu.p_data[xx], aid.data(), aid.size()); cmdApdu.p_data[xx + aid.size()] = 0x00; // Le status = StEse_Transceive(&cmdApdu, &rspApdu); } if (status != ESESTATUS_SUCCESS) { /*Transceive failed*/ sestatus = SecureElementStatus::IOERROR; } else { uint8_t sw1 = rspApdu.p_data[rspApdu.len - 2]; uint8_t sw2 = rspApdu.p_data[rspApdu.len - 1]; /*Return response on success, empty vector on failure*/ /*Status is success*/ if (sw1 == 0x90 && sw2 == 0x00) { /*Copy the response including status word*/ resApduBuff.selectResponse.resize(rspApdu.len); memcpy(&resApduBuff.selectResponse[0], rspApdu.p_data, rspApdu.len); sestatus = SecureElementStatus::SUCCESS; } /*AID provided doesn't match any applet on the secure element*/ else if (sw1 == 0x6A && sw2 == 0x82) { sestatus = SecureElementStatus::NO_SUCH_ELEMENT_ERROR; } /*Operation provided by the P2 parameter is not permitted by the applet.*/ else if (sw1 == 0x6A && sw2 == 0x86) { sestatus = SecureElementStatus::UNSUPPORTED_OPERATION; } } if (sestatus != SecureElementStatus::SUCCESS) { /* if the SE is unresponsive, reset it */ if (sestatus == SecureElementStatus::IOERROR) { seHalResetSe(); } else { STLOG_HAL_E("%s: Select APDU failed! Close channel..", __func__); SecureElementStatus closeChannelStatus = closeChannel(resApduBuff.channelNumber); if (closeChannelStatus != SecureElementStatus::SUCCESS) { STLOG_HAL_E("%s: closeChannel Failed", __func__); } else { resApduBuff.channelNumber = 0xff; } } } _hidl_cb(resApduBuff, sestatus); free(cmdApdu.p_data); free(rspApdu.p_data); STLOG_HAL_V("%s: Exit", __func__); OpenLogicalChannelProcessing = false; return Void(); } Return SecureElement::openBasicChannel(const hidl_vec& aid, uint8_t p2, openBasicChannel_cb _hidl_cb) { hidl_vec result; OpenBasicChannelProcessing = true; STLOG_HAL_D("%s: Enter", __func__); if (!isSeInitialized()) { ESESTATUS status = seHalInit(); if (status != ESESTATUS_SUCCESS) { STLOG_HAL_E("%s: seHalInit Failed!!!", __func__); _hidl_cb(result, SecureElementStatus::IOERROR); OpenBasicChannelProcessing = false; return Void(); } } SecureElementStatus sestatus = SecureElementStatus::IOERROR; ESESTATUS status = ESESTATUS_FAILED; StEse_data cmdApdu; StEse_data rspApdu; memset(&cmdApdu, 0x00, sizeof(StEse_data)); memset(&rspApdu, 0x00, sizeof(StEse_data)); cmdApdu.len = (int32_t)(6 + aid.size()); cmdApdu.p_data = (uint8_t*)malloc(cmdApdu.len * sizeof(uint8_t)); if (cmdApdu.p_data != NULL) { uint8_t xx = 0; cmdApdu.p_data[xx++] = 0x00; // basic channel cmdApdu.p_data[xx++] = 0xA4; // INS cmdApdu.p_data[xx++] = 0x04; // P1 cmdApdu.p_data[xx++] = p2; // P2 cmdApdu.p_data[xx++] = aid.size(); // Lc memcpy(&cmdApdu.p_data[xx], aid.data(), aid.size()); cmdApdu.p_data[xx + aid.size()] = 0x00; // Le status = StEse_Transceive(&cmdApdu, &rspApdu); } if (status != ESESTATUS_SUCCESS) { /* Transceive failed */ sestatus = SecureElementStatus::IOERROR; } else { uint8_t sw1 = rspApdu.p_data[rspApdu.len - 2]; uint8_t sw2 = rspApdu.p_data[rspApdu.len - 1]; /*Return response on success, empty vector on failure*/ /*Status is success*/ if ((sw1 == 0x90) && (sw2 == 0x00)) { /*Copy the response including status word*/ result.resize(rspApdu.len); memcpy(&result[0], rspApdu.p_data, rspApdu.len); /*Set basic channel reference if it is not set */ if (!mOpenedChannels[0]) { mOpenedChannels[0] = true; mOpenedchannelCount++; } sestatus = SecureElementStatus::SUCCESS; } /*AID provided doesn't match any applet on the secure element*/ else if (sw1 == 0x6A && sw2 == 0x82) { sestatus = SecureElementStatus::NO_SUCH_ELEMENT_ERROR; } /*Operation provided by the P2 parameter is not permitted by the applet.*/ else if (sw1 == 0x6A && sw2 == 0x86) { sestatus = SecureElementStatus::UNSUPPORTED_OPERATION; } } /* if the SE is unresponsive, reset it */ if (sestatus == SecureElementStatus::IOERROR) { seHalResetSe(); } if ((sestatus != SecureElementStatus::SUCCESS) && mOpenedChannels[0]) { SecureElementStatus closeChannelStatus = closeChannel(DEFAULT_BASIC_CHANNEL); if (closeChannelStatus != SecureElementStatus::SUCCESS) { STLOG_HAL_E("%s: closeChannel Failed", __func__); } } _hidl_cb(result, sestatus); free(cmdApdu.p_data); free(rspApdu.p_data); STLOG_HAL_V("%s: Exit", __func__); OpenBasicChannelProcessing = false; return Void(); } Return<::android::hardware::secure_element::V1_0::SecureElementStatus> SecureElement::closeChannel(uint8_t channelNumber) { ESESTATUS status = ESESTATUS_FAILED; SecureElementStatus sestatus = SecureElementStatus::FAILED; StEse_data cmdApdu; StEse_data rspApdu; STLOG_HAL_D("%s: Enter : %d", __func__, channelNumber); if ((channelNumber < DEFAULT_BASIC_CHANNEL) || (channelNumber >= MAX_LOGICAL_CHANNELS) || (mOpenedChannels[channelNumber] == false)) { STLOG_HAL_E("%s: invalid channel!!!", __func__); sestatus = SecureElementStatus::FAILED; } else if (channelNumber > DEFAULT_BASIC_CHANNEL) { memset(&cmdApdu, 0x00, sizeof(StEse_data)); memset(&rspApdu, 0x00, sizeof(StEse_data)); cmdApdu.p_data = (uint8_t*)malloc(5 * sizeof(uint8_t)); if (cmdApdu.p_data != NULL) { uint8_t xx = 0; cmdApdu.p_data[xx++] = channelNumber; cmdApdu.p_data[xx++] = 0x70; // INS cmdApdu.p_data[xx++] = 0x80; // P1 cmdApdu.p_data[xx++] = channelNumber; // P2 cmdApdu.p_data[xx++] = 0x00; // Lc cmdApdu.len = xx; status = StEse_Transceive(&cmdApdu, &rspApdu); } if (status != ESESTATUS_SUCCESS) { sestatus = SecureElementStatus::FAILED; } else if ((rspApdu.p_data[rspApdu.len - 2] == 0x90) && (rspApdu.p_data[rspApdu.len - 1] == 0x00)) { sestatus = SecureElementStatus::SUCCESS; } else { sestatus = SecureElementStatus::FAILED; } free(cmdApdu.p_data); free(rspApdu.p_data); } if ((channelNumber == DEFAULT_BASIC_CHANNEL) || (sestatus == SecureElementStatus::SUCCESS)) { STLOG_HAL_D("%s: Closing channel : %d is successful ", __func__, channelNumber); mOpenedChannels[channelNumber] = false; mOpenedchannelCount--; /*If there are no channels remaining close secureElement*/ if ((mOpenedchannelCount == 0) && !OpenLogicalChannelProcessing && !OpenBasicChannelProcessing) { sestatus = seHalDeInit(); } else { sestatus = SecureElementStatus::SUCCESS; } } STLOG_HAL_V("%s: Exit", __func__); return sestatus; } void SecureElement::serviceDied(uint64_t /*cookie*/, const wp& /*who*/) { STLOG_HAL_E("%s: SecureElement serviceDied!!!", __func__); SecureElementStatus sestatus = seHalDeInit(); if (sestatus != SecureElementStatus::SUCCESS) { STLOG_HAL_E("%s: seHalDeInit Failed!!!", __func__); } if (mCallbackV1_1 != nullptr) { mCallbackV1_1->unlinkToDeath(this); mCallbackV1_1 = nullptr; } } bool SecureElement::isSeInitialized() { return StEseApi_isOpen(); } ESESTATUS SecureElement::seHalInit() { ESESTATUS status = ESESTATUS_SUCCESS; STLOG_HAL_D("%s: Enter", __func__); status = StEse_init(); if (status != ESESTATUS_SUCCESS) { STLOG_HAL_E("%s: SecureElement open failed!!!", __func__); } STLOG_HAL_V("%s: Exit", __func__); return status; } void SecureElement::seHalResetSe() { ESESTATUS status = ESESTATUS_SUCCESS; STLOG_HAL_D("%s: Enter", __func__); if (!isSeInitialized()) { ESESTATUS status = seHalInit(); if (status != ESESTATUS_SUCCESS) { STLOG_HAL_E("%s: seHalInit Failed!!!", __func__); } } if (status == ESESTATUS_SUCCESS) { mCallbackV1_1->onStateChange_1_1(false, "reset the SE"); status = StEse_Reset(); if (status != ESESTATUS_SUCCESS) { STLOG_HAL_E("%s: SecureElement reset failed!!", __func__); } else { for (uint8_t xx = 0; xx < MAX_LOGICAL_CHANNELS; xx++) { mOpenedChannels[xx] = false; } mOpenedchannelCount = 0; mCallbackV1_1->onStateChange_1_1(true, "SE initialized"); } } STLOG_HAL_V("%s: Exit", __func__); } Return<::android::hardware::secure_element::V1_0::SecureElementStatus> SecureElement::seHalDeInit() { STLOG_HAL_D("%s: Enter", __func__); ESESTATUS status = ESESTATUS_SUCCESS; SecureElementStatus sestatus = SecureElementStatus::FAILED; status = StEse_close(); if (status != ESESTATUS_SUCCESS) { sestatus = SecureElementStatus::FAILED; } else { sestatus = SecureElementStatus::SUCCESS; for (uint8_t xx = 0; xx < MAX_LOGICAL_CHANNELS; xx++) { mOpenedChannels[xx] = false; } mOpenedchannelCount = 0; } STLOG_HAL_V("%s: Exit", __func__); return sestatus; } Return<::android::hardware::secure_element::V1_0::SecureElementStatus> SecureElement::reset() { int ret = 0; ESESTATUS status = ESESTATUS_SUCCESS; SecureElementStatus sestatus = SecureElementStatus::FAILED; std::string valueStr = android::base::GetProperty("persist.vendor.se.streset", ""); STLOG_HAL_D("%s: Enter", __func__); if (!isSeInitialized()) { ESESTATUS status = seHalInit(); if (status != ESESTATUS_SUCCESS) { STLOG_HAL_E("%s: seHalInit Failed!!!", __func__); if (valueStr.length() > 0) { valueStr = VENDOR_LIB_PATH + valueStr + VENDOR_LIB_EXT; void* stdll = dlopen(valueStr.c_str(), RTLD_NOW); if (stdll) { STEseReset fn = (STEseReset)dlsym(stdll, "direct_reset"); if (fn) { STLOG_HAL_E("STReset direct reset"); ret = fn(); STLOG_HAL_E("STReset result=%d", ret); if (ret == 0) { STLOG_HAL_E("STReset pass, retry seHalInit()"); status = seHalInit(); } } } else { STLOG_HAL_D("%s not found, do nothing.", valueStr.c_str()); } } } } if (status == ESESTATUS_SUCCESS) { mCallbackV1_1->onStateChange_1_1(false, "reset the SE"); status = StEse_Reset(); if (status != ESESTATUS_SUCCESS) { STLOG_HAL_E("%s: SecureElement reset failed!!", __func__); } else { sestatus = SecureElementStatus::SUCCESS; for (uint8_t xx = 0; xx < MAX_LOGICAL_CHANNELS; xx++) { mOpenedChannels[xx] = false; } mOpenedchannelCount = 0; mCallbackV1_1->onStateChange_1_1(true, "SE initialized"); } } STLOG_HAL_V("%s: Exit", __func__); return sestatus; } } // namespace implementation } // namespace V1_2 } // namespace secure_element } // namespace hardware } // namespace android