diff options
author | android-build-team Robot <android-build-team-robot@google.com> | 2019-03-16 23:16:32 +0000 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2019-03-16 23:16:32 +0000 |
commit | bfa84fa484d566a3a32751186d714748d5631e17 (patch) | |
tree | 1359627649e9e6060c7c97dc315aee10227a5598 | |
parent | f2580ed3eda8bcb9f5852631fba0c33da7d1a754 (diff) | |
parent | 52caef057413dca49b49c243ca9f6c9db5123673 (diff) | |
download | secure_element-bfa84fa484d566a3a32751186d714748d5631e17.tar.gz |
Snap for 5381581 from 52caef057413dca49b49c243ca9f6c9db5123673 to qt-release
Change-Id: I13d34321d91b1df0dd3634575954055db9c143bd
-rwxr-xr-x | 1.0/SecureElement.cpp | 11 | ||||
-rwxr-xr-x | 1.0/SecureElement.h | 3 | ||||
-rwxr-xr-x | 1.1/NxpEseService.cpp | 60 | ||||
-rwxr-xr-x | 1.1/SecureElement.cpp | 503 | ||||
-rwxr-xr-x | 1.1/SecureElement.h | 89 | ||||
-rw-r--r-- | 1.1/android.hardware.secure_element@1.1-service-disabled.rc | 5 | ||||
-rw-r--r-- | 1.1/android.hardware.secure_element@1.1-service.rc | 5 | ||||
-rwxr-xr-x | Android.bp | 43 | ||||
-rwxr-xr-x | ls_client/inc/LsClient.h | 25 | ||||
-rwxr-xr-x | ls_client/inc/LsLib.h | 11 | ||||
-rwxr-xr-x | ls_client/src/LsClient.cpp | 197 | ||||
-rwxr-xr-x | ls_client/src/LsLib.cpp | 54 |
12 files changed, 982 insertions, 24 deletions
diff --git a/1.0/SecureElement.cpp b/1.0/SecureElement.cpp index 2ca4e7f..6a38a25 100755 --- a/1.0/SecureElement.cpp +++ b/1.0/SecureElement.cpp @@ -32,6 +32,10 @@ namespace implementation { sp<V1_0::ISecureElementHalCallback> SecureElement::mCallbackV1_0 = nullptr; +static void onLSCompleted(bool result, std::string reason, void* arg) { + ((SecureElement*)arg)->onStateChange(result, reason); +} + SecureElement::SecureElement() : mOpenedchannelCount(0), mOpenedChannels{false, false, false, false} {} @@ -61,7 +65,7 @@ Return<void> SecureElement::init( return Void(); } - LSCSTATUS lsStatus = LSC_doDownload(clientCallback); + LSCSTATUS lsStatus = LSC_doDownload(onLSCompleted, (void*)this); /* * LSC_doDownload returns LSCSTATUS_FAILED in case thread creation fails. * So return callback as false. @@ -439,6 +443,11 @@ SecureElement::seHalDeInit() { return sestatus; } +void SecureElement::onStateChange(bool result, std::string reason) { + ALOGD("%s: result: %d, reaon= %s", __func__, result, reason.c_str()); + mCallbackV1_0->onStateChange(result); +} + } // namespace implementation } // namespace V1_0 } // namespace secure_element diff --git a/1.0/SecureElement.h b/1.0/SecureElement.h index 6e5c4a7..a15028a 100755 --- a/1.0/SecureElement.h +++ b/1.0/SecureElement.h @@ -21,6 +21,8 @@ #include <android/hardware/secure_element/1.0/ISecureElement.h> #include <hidl/MQDescriptor.h> #include <hidl/Status.h> +#include <string> + #include "phNxpEse_Api.h" namespace android { @@ -61,6 +63,7 @@ struct SecureElement : public ISecureElement, public hidl_death_recipient { Return<::android::hardware::secure_element::V1_0::SecureElementStatus> closeChannel(uint8_t channelNumber) override; void serviceDied(uint64_t /*cookie*/, const wp<IBase>& /*who*/) override; + void onStateChange(bool result, std::string reason); private: uint8_t mOpenedchannelCount = 0; diff --git a/1.1/NxpEseService.cpp b/1.1/NxpEseService.cpp new file mode 100755 index 0000000..595f11e --- /dev/null +++ b/1.1/NxpEseService.cpp @@ -0,0 +1,60 @@ +/****************************************************************************** + * + * 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 "nxpese@1.0-service" +#include <android/hardware/secure_element/1.1/ISecureElement.h> +#include <hidl/LegacySupport.h> +#include <log/log.h> +#include <vendor/nxp/nxpese/1.0/INxpEse.h> + +#include "NxpEse.h" +#include "SecureElement.h" + +// Generated HIDL files +using android::OK; +using android::sp; +using android::status_t; +using android::hardware::configureRpcThreadpool; +using android::hardware::joinRpcThreadpool; +using android::hardware::secure_element::V1_1::ISecureElement; +using android::hardware::secure_element::V1_1::implementation::SecureElement; +using vendor::nxp::nxpese::V1_0::INxpEse; +using vendor::nxp::nxpese::V1_0::implementation::NxpEse; + +int main() { + ALOGD("Secure Element HAL Service 1.1 is starting."); + sp<ISecureElement> se_service = new SecureElement(); + configureRpcThreadpool(1, true /*callerWillJoin*/); + status_t status = se_service->registerAsService("eSE1"); + if (status != OK) { + LOG_ALWAYS_FATAL( + "Could not register service for Secure Element HAL Iface (%d).", + status); + return -1; + } + sp<INxpEse> nxp_se_service = new NxpEse(); + status = nxp_se_service->registerAsService(); + if (status != OK) { + LOG_ALWAYS_FATAL( + "Could not register service for Power Secure Element Extn Iface (%d).", + status); + return -1; + } + ALOGD("Secure Element Service is ready"); + joinRpcThreadpool(); + return 1; +} diff --git a/1.1/SecureElement.cpp b/1.1/SecureElement.cpp new file mode 100755 index 0000000..e04b8ba --- /dev/null +++ b/1.1/SecureElement.cpp @@ -0,0 +1,503 @@ +/****************************************************************************** + * + * 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 "NxpEseHal" +#include <log/log.h> + +#include "LsClient.h" +#include "SecureElement.h" +#include "phNxpEse_Api.h" + +extern bool ese_debug_enabled; + +namespace android { +namespace hardware { +namespace secure_element { +namespace V1_1 { +namespace implementation { + +sp<V1_0::ISecureElementHalCallback> SecureElement::mCallbackV1_0 = nullptr; +sp<V1_1::ISecureElementHalCallback> SecureElement::mCallbackV1_1 = nullptr; + +static void onLSCompleted(bool result, std::string reason, void* arg) { + ((SecureElement*)arg)->onStateChange(result, reason); +} + +SecureElement::SecureElement() + : mOpenedchannelCount(0), mOpenedChannels{false, false, false, false} {} + +Return<void> SecureElement::init( + const sp<V1_0::ISecureElementHalCallback>& clientCallback) { + ESESTATUS status = ESESTATUS_SUCCESS; + + if (clientCallback == nullptr) { + return Void(); + } else { + mCallbackV1_0 = clientCallback; + mCallbackV1_1 = nullptr; + if (!mCallbackV1_0->linkToDeath(this, 0 /*cookie*/)) { + ALOGE("%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(); + } + + LSCSTATUS lsStatus = LSC_doDownload(onLSCompleted, (void*)this); + /* + * LSC_doDownload returns LSCSTATUS_FAILED in case thread creation fails. + * So return callback as false. + * Otherwise callback will be called in LSDownload module. + */ + if (lsStatus != LSCSTATUS_SUCCESS) { + ALOGE("%s: LSDownload thread creation failed!!!", __func__); + SecureElementStatus sestatus = seHalDeInit(); + if (sestatus != SecureElementStatus::SUCCESS) { + ALOGE("%s: seHalDeInit failed!!!", __func__); + } + clientCallback->onStateChange(false); + } + return Void(); +} + +Return<void> SecureElement::init_1_1( + const sp<V1_1::ISecureElementHalCallback>& clientCallback) { + ESESTATUS status = ESESTATUS_SUCCESS; + + if (clientCallback == nullptr) { + return Void(); + } else { + mCallbackV1_1 = clientCallback; + mCallbackV1_0 = nullptr; + if (!mCallbackV1_1->linkToDeath(this, 0 /*cookie*/)) { + ALOGE("%s: Failed to register death notification", __func__); + } + } + if (isSeInitialized()) { + clientCallback->onStateChange_1_1(true, "NXP SE HAL init ok"); + return Void(); + } + + status = seHalInit(); + if (status != ESESTATUS_SUCCESS) { + clientCallback->onStateChange_1_1(false, "NXP SE HAL init failed"); + return Void(); + } + + LSCSTATUS lsStatus = LSC_doDownload(onLSCompleted, (void*)this); + /* + * LSC_doDownload returns LSCSTATUS_FAILED in case thread creation fails. + * So return callback as false. + * Otherwise callback will be called in LSDownload module. + */ + if (lsStatus != LSCSTATUS_SUCCESS) { + ALOGE("%s: LSDownload thread creation failed!!!", __func__); + SecureElementStatus sestatus = seHalDeInit(); + if (sestatus != SecureElementStatus::SUCCESS) { + ALOGE("%s: seHalDeInit failed!!!", __func__); + } + clientCallback->onStateChange_1_1(false, + "Failed to create LS download thread"); + } + return Void(); +} + +Return<void> SecureElement::getAtr(getAtr_cb _hidl_cb) { + hidl_vec<uint8_t> response; + _hidl_cb(response); + return Void(); +} + +Return<bool> SecureElement::isCardPresent() { return true; } + +Return<void> SecureElement::transmit(const hidl_vec<uint8_t>& data, + transmit_cb _hidl_cb) { + ESESTATUS status = ESESTATUS_FAILED; + phNxpEse_data cmdApdu; + phNxpEse_data rspApdu; + phNxpEse_memset(&cmdApdu, 0x00, sizeof(phNxpEse_data)); + phNxpEse_memset(&rspApdu, 0x00, sizeof(phNxpEse_data)); + + cmdApdu.len = data.size(); + if (cmdApdu.len >= MIN_APDU_LENGTH) { + cmdApdu.p_data = (uint8_t*)phNxpEse_memalloc(data.size() * sizeof(uint8_t)); + memcpy(cmdApdu.p_data, data.data(), cmdApdu.len); + status = phNxpEse_Transceive(&cmdApdu, &rspApdu); + } + + hidl_vec<uint8_t> result; + if (status != ESESTATUS_SUCCESS) { + ALOGE("%s: transmit failed!!!", __func__); + } else { + result.resize(rspApdu.len); + memcpy(&result[0], rspApdu.p_data, rspApdu.len); + } + _hidl_cb(result); + phNxpEse_free(cmdApdu.p_data); + phNxpEse_free(rspApdu.p_data); + return Void(); +} + +Return<void> SecureElement::openLogicalChannel(const hidl_vec<uint8_t>& aid, + uint8_t p2, + openLogicalChannel_cb _hidl_cb) { + hidl_vec<uint8_t> manageChannelCommand = {0x00, 0x70, 0x00, 0x00, 0x01}; + + LogicalChannelResponse resApduBuff; + resApduBuff.channelNumber = 0xff; + memset(&resApduBuff, 0x00, sizeof(resApduBuff)); + + if (!isSeInitialized()) { + ESESTATUS status = seHalInit(); + if (status != ESESTATUS_SUCCESS) { + ALOGE("%s: seHalInit Failed!!!", __func__); + _hidl_cb(resApduBuff, SecureElementStatus::IOERROR); + return Void(); + } + } + + SecureElementStatus sestatus = SecureElementStatus::IOERROR; + ESESTATUS status = ESESTATUS_FAILED; + phNxpEse_data cmdApdu; + phNxpEse_data rspApdu; + + phNxpEse_memset(&cmdApdu, 0x00, sizeof(phNxpEse_data)); + phNxpEse_memset(&rspApdu, 0x00, sizeof(phNxpEse_data)); + + cmdApdu.len = manageChannelCommand.size(); + cmdApdu.p_data = (uint8_t*)phNxpEse_memalloc(manageChannelCommand.size() * + sizeof(uint8_t)); + if (cmdApdu.p_data != NULL) { + memcpy(cmdApdu.p_data, manageChannelCommand.data(), cmdApdu.len); + status = phNxpEse_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*/ + phNxpEse_free(cmdApdu.p_data); + phNxpEse_free(rspApdu.p_data); + + if (sestatus != SecureElementStatus::SUCCESS) { + /*If first logical channel open fails, DeInit SE*/ + if (isSeInitialized() && (mOpenedchannelCount == 0)) { + SecureElementStatus deInitStatus = seHalDeInit(); + if (deInitStatus != SecureElementStatus::SUCCESS) { + ALOGE("%s: seDeInit Failed", __func__); + } + } + /*If manageChanle is failed in any of above cases + send the callback and return*/ + _hidl_cb(resApduBuff, sestatus); + return Void(); + } + + ALOGD_IF(ese_debug_enabled, "%s: Sending selectApdu", __func__); + /*Reset variables if manageChannel is success*/ + sestatus = SecureElementStatus::IOERROR; + status = ESESTATUS_FAILED; + + phNxpEse_memset(&cmdApdu, 0x00, sizeof(phNxpEse_data)); + phNxpEse_memset(&rspApdu, 0x00, sizeof(phNxpEse_data)); + + cmdApdu.len = (int32_t)(5 + aid.size()); + cmdApdu.p_data = (uint8_t*)phNxpEse_memalloc(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()); + + status = phNxpEse_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) { + SecureElementStatus closeChannelStatus = + closeChannel(resApduBuff.channelNumber); + if (closeChannelStatus != SecureElementStatus::SUCCESS) { + ALOGE("%s: closeChannel Failed", __func__); + } else { + resApduBuff.channelNumber = 0xff; + } + } + _hidl_cb(resApduBuff, sestatus); + phNxpEse_free(cmdApdu.p_data); + phNxpEse_free(rspApdu.p_data); + + return Void(); +} + +Return<void> SecureElement::openBasicChannel(const hidl_vec<uint8_t>& aid, + uint8_t p2, + openBasicChannel_cb _hidl_cb) { + hidl_vec<uint8_t> result; + + if (!isSeInitialized()) { + ESESTATUS status = seHalInit(); + if (status != ESESTATUS_SUCCESS) { + ALOGE("%s: seHalInit Failed!!!", __func__); + _hidl_cb(result, SecureElementStatus::IOERROR); + return Void(); + } + } + + SecureElementStatus sestatus = SecureElementStatus::IOERROR; + ESESTATUS status = ESESTATUS_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 + aid.size()); + cmdApdu.p_data = (uint8_t*)phNxpEse_memalloc(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()); + + status = phNxpEse_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 (sestatus != SecureElementStatus::SUCCESS) { + SecureElementStatus closeStatus = SecureElementStatus::IOERROR; + /*If first basic channel open fails, DeInit SE*/ + if ((mOpenedChannels[DEFAULT_BASIC_CHANNEL] == false) && + (mOpenedchannelCount == 0)) { + closeStatus = seHalDeInit(); + } else { + closeStatus = closeChannel(DEFAULT_BASIC_CHANNEL); + } + if (closeStatus != SecureElementStatus::SUCCESS) { + ALOGE("%s: close Failed", __func__); + } + } + _hidl_cb(result, sestatus); + phNxpEse_free(cmdApdu.p_data); + phNxpEse_free(rspApdu.p_data); + return Void(); +} + +Return<SecureElementStatus> SecureElement::closeChannel(uint8_t channelNumber) { + ESESTATUS status = ESESTATUS_FAILED; + SecureElementStatus sestatus = SecureElementStatus::FAILED; + + phNxpEse_data cmdApdu; + phNxpEse_data rspApdu; + + if ((channelNumber < DEFAULT_BASIC_CHANNEL) || + (channelNumber >= MAX_LOGICAL_CHANNELS) || + (mOpenedChannels[channelNumber] == false)) { + ALOGE("%s: invalid channel!!!", __func__); + sestatus = SecureElementStatus::FAILED; + } else if (channelNumber > DEFAULT_BASIC_CHANNEL) { + phNxpEse_memset(&cmdApdu, 0x00, sizeof(phNxpEse_data)); + phNxpEse_memset(&rspApdu, 0x00, sizeof(phNxpEse_data)); + cmdApdu.p_data = (uint8_t*)phNxpEse_memalloc(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 = phNxpEse_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; + } + phNxpEse_free(cmdApdu.p_data); + phNxpEse_free(rspApdu.p_data); + } + + if ((channelNumber == DEFAULT_BASIC_CHANNEL) || + (sestatus == SecureElementStatus::SUCCESS)) { + if (mOpenedChannels[channelNumber] != false) mOpenedchannelCount--; + mOpenedChannels[channelNumber] = false; + /*If there are no channels remaining close secureElement*/ + if (mOpenedchannelCount == 0) { + sestatus = seHalDeInit(); + } else { + sestatus = SecureElementStatus::SUCCESS; + } + } + return sestatus; +} + +void SecureElement::serviceDied(uint64_t /*cookie*/, const wp<IBase>& /*who*/) { + ALOGE("%s: SecureElement serviceDied!!!", __func__); + SecureElementStatus sestatus = seHalDeInit(); + if (sestatus != SecureElementStatus::SUCCESS) { + ALOGE("%s: seHalDeInit Faliled!!!", __func__); + } + if (mCallbackV1_0 != nullptr) { + mCallbackV1_0->unlinkToDeath(this); + mCallbackV1_0 = nullptr; + } + if (mCallbackV1_1 != nullptr) { + mCallbackV1_1->unlinkToDeath(this); + mCallbackV1_1 = nullptr; + } +} + +bool SecureElement::isSeInitialized() { return phNxpEse_isOpen(); } + +ESESTATUS SecureElement::seHalInit() { + ESESTATUS status = ESESTATUS_SUCCESS; + phNxpEse_initParams initParams; + memset(&initParams, 0x00, sizeof(phNxpEse_initParams)); + initParams.initMode = ESE_MODE_NORMAL; + + status = phNxpEse_open(initParams); + if (status != ESESTATUS_SUCCESS) { + ALOGE("%s: SecureElement open failed!!!", __func__); + } else { + status = phNxpEse_init(initParams); + if (status != ESESTATUS_SUCCESS) { + ALOGE("%s: SecureElement init failed!!!", __func__); + } + } + return status; +} + +Return<SecureElementStatus> SecureElement::seHalDeInit() { + ESESTATUS status = ESESTATUS_SUCCESS; + SecureElementStatus sestatus = SecureElementStatus::FAILED; + status = phNxpEse_deInit(); + if (status != ESESTATUS_SUCCESS) { + sestatus = SecureElementStatus::FAILED; + } else { + status = phNxpEse_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; + } + } + return sestatus; +} + +void SecureElement::onStateChange(bool result, std::string reason) { + ALOGD("%s: result: %d, reaon= %s", __func__, result, reason.c_str()); + if (mCallbackV1_1 != nullptr) { + mCallbackV1_1->onStateChange_1_1(result, reason); + } else if (mCallbackV1_0 != nullptr) { + mCallbackV1_0->onStateChange(result); + } +} + +} // namespace implementation +} // namespace V1_1 +} // namespace secure_element +} // namespace hardware +} // namespace android diff --git a/1.1/SecureElement.h b/1.1/SecureElement.h new file mode 100755 index 0000000..d36b03f --- /dev/null +++ b/1.1/SecureElement.h @@ -0,0 +1,89 @@ +/****************************************************************************** + * + * 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. + * + ******************************************************************************/ +#ifndef ANDROID_HARDWARE_SECURE_ELEMENT_V1_1_SECUREELEMENT_H +#define ANDROID_HARDWARE_SECURE_ELEMENT_V1_1_SECUREELEMENT_H + +#include <android/hardware/secure_element/1.0/types.h> +#include <android/hardware/secure_element/1.1/ISecureElement.h> +#include <hidl/MQDescriptor.h> +#include <hidl/Status.h> +#include <string> + +#include "phNxpEse_Api.h" + +namespace android { +namespace hardware { +namespace secure_element { +namespace V1_1 { +namespace implementation { + +using ::android::sp; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::secure_element::V1_0::LogicalChannelResponse; +using ::android::hardware::secure_element::V1_0::SecureElementStatus; +using ::android::hardware::secure_element::V1_1::ISecureElement; +using ::android::hidl::base::V1_0::IBase; + +#ifndef MAX_LOGICAL_CHANNELS +#define MAX_LOGICAL_CHANNELS 0x04 +#endif +#ifndef MIN_APDU_LENGTH +#define MIN_APDU_LENGTH 0x04 +#endif +#ifndef DEFAULT_BASIC_CHANNEL +#define DEFAULT_BASIC_CHANNEL 0x00 +#endif + +struct SecureElement : public V1_1::ISecureElement, + public hidl_death_recipient { + SecureElement(); + Return<void> init( + const sp<V1_0::ISecureElementHalCallback>& clientCallback) override; + Return<void> init_1_1( + const sp<V1_1::ISecureElementHalCallback>& clientCallback) override; + Return<void> getAtr(getAtr_cb _hidl_cb) override; + Return<bool> isCardPresent() override; + Return<void> transmit(const hidl_vec<uint8_t>& data, + transmit_cb _hidl_cb) override; + Return<void> openLogicalChannel(const hidl_vec<uint8_t>& aid, uint8_t p2, + openLogicalChannel_cb _hidl_cb) override; + Return<void> openBasicChannel(const hidl_vec<uint8_t>& aid, uint8_t p2, + openBasicChannel_cb _hidl_cb) override; + Return<SecureElementStatus> closeChannel(uint8_t channelNumber) override; + void serviceDied(uint64_t /*cookie*/, const wp<IBase>& /*who*/) override; + void onStateChange(bool result, std::string reason); + + private: + uint8_t mOpenedchannelCount = 0; + bool mOpenedChannels[MAX_LOGICAL_CHANNELS]; + static sp<V1_0::ISecureElementHalCallback> mCallbackV1_0; + static sp<V1_1::ISecureElementHalCallback> mCallbackV1_1; + Return<SecureElementStatus> seHalDeInit(); + ESESTATUS seHalInit(); + bool isSeInitialized(); +}; + +} // namespace implementation +} // namespace V1_1 +} // namespace secure_element +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_SECURE_ELEMENT_V1_1_SECUREELEMENT_H diff --git a/1.1/android.hardware.secure_element@1.1-service-disabled.rc b/1.1/android.hardware.secure_element@1.1-service-disabled.rc new file mode 100644 index 0000000..d17201f --- /dev/null +++ b/1.1/android.hardware.secure_element@1.1-service-disabled.rc @@ -0,0 +1,5 @@ +service vendor.secure_element_hal_service_1_1 /vendor/bin/hw/android.hardware.secure_element@1.1-service-disabled + disabled + interface android.hardware.secure_element@1.1::ISecureElement eSE1 + user secure_element + group secure_element diff --git a/1.1/android.hardware.secure_element@1.1-service.rc b/1.1/android.hardware.secure_element@1.1-service.rc new file mode 100644 index 0000000..388fffd --- /dev/null +++ b/1.1/android.hardware.secure_element@1.1-service.rc @@ -0,0 +1,5 @@ +service vendor.secure_element_hal_service_1_1 /vendor/bin/hw/android.hardware.secure_element@1.1-service + class hal + interface android.hardware.secure_element@1.1::ISecureElement eSE1 + user secure_element + group secure_element @@ -42,7 +42,6 @@ cc_library_shared { shared_libs: [ "android.hardware.nfc@1.0", "android.hardware.nfc@1.1", - "android.hardware.secure_element@1.0", "libcutils", "libhardware", "libhidlbase", @@ -70,7 +69,6 @@ cc_library_shared { shared_libs: [ "ese_spi_nxp", - "android.hardware.secure_element@1.0", "libcutils", "liblog", "libhidlbase", @@ -81,6 +79,35 @@ cc_library_shared { } cc_defaults { + name: "android.hardware.secure_element@1.1_defaults", + relative_install_path: "hw", + proprietary: true, + defaults: ["hidl_defaults"], + srcs: [ + "1.1/NxpEseService.cpp", + "1.1/SecureElement.cpp", + "extns/impl/NxpEse.cpp", + ], + + shared_libs: [ + "android.hardware.secure_element@1.0", + "android.hardware.secure_element@1.1", + "ese_spi_nxp", + "libbase", + "ls_client", + "libcutils", + "libhardware", + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "vendor.nxp.nxpese@1.0", + "vendor.nxp.nxpnfc@1.0", + ], +} + +cc_defaults { name: "android.hardware.secure_element@1.0_defaults", relative_install_path: "hw", proprietary: true, @@ -119,3 +146,15 @@ cc_binary { init_rc: ["1.0/android.hardware.secure_element@1.0-service-disabled.rc"], defaults: ["android.hardware.secure_element@1.0_defaults"], } + +cc_binary { + name: "android.hardware.secure_element@1.1-service", + init_rc: ["1.1/android.hardware.secure_element@1.1-service.rc"], + defaults: ["android.hardware.secure_element@1.1_defaults"], +} + +cc_binary { + name: "android.hardware.secure_element@1.1-service-disabled", + init_rc: ["1.1/android.hardware.secure_element@1.1-service-disabled.rc"], + defaults: ["android.hardware.secure_element@1.1_defaults"], +} diff --git a/ls_client/inc/LsClient.h b/ls_client/inc/LsClient.h index 01facdb..b4fa43e 100755 --- a/ls_client/inc/LsClient.h +++ b/ls_client/inc/LsClient.h @@ -19,7 +19,7 @@ #ifndef LSCLIENT_H_ #define LSCLIENT_H_ -#include <android/hardware/secure_element/1.0/ISecureElementHalCallback.h> +#include <string> typedef enum { LSCSTATUS_SUCCESS = (0x0000), @@ -29,18 +29,25 @@ typedef enum { LSCSTATUS_HASH_SLOT_INVALID = (0x0007) } LSCSTATUS; -using ::android::hardware::secure_element::V1_0::ISecureElementHalCallback; - /******************************************************************************* ** -** Function: LSC_doDownload -** -** Description: Perform LS during hal init +** Function: LSC_onCompletedCallback ** -** Returns: SUCCESS of ok +** Description: callback function when Loader Service Scripts thread is done ** *******************************************************************************/ -LSCSTATUS LSC_doDownload( - const android::sp<ISecureElementHalCallback>& clientCallback); +typedef void (*LSC_onCompletedCallback)(bool result, std::string reason, + void* args); + +/******************************************************************************* + ** + ** Function: LSC_doDownload + ** + ** Description: Start LS download process + ** + ** Returns: SUCCESS if ok + ** + *******************************************************************************/ +LSCSTATUS LSC_doDownload(LSC_onCompletedCallback callback, void* arg); #endif /* LSCLIENT_H_ */ diff --git a/ls_client/inc/LsLib.h b/ls_client/inc/LsLib.h index 1bb9214..b5002cc 100755 --- a/ls_client/inc/LsLib.h +++ b/ls_client/inc/LsLib.h @@ -510,6 +510,17 @@ LSCSTATUS LSC_UpdateLsHash(uint8_t* hash, long hashLen, uint8_t slotId); /******************************************************************************* ** +** Function: LSC_ReadLscInfo +** +** Description: Read the info of LS applet +** +** Returns: SUCCESS/FAILURE +** +*******************************************************************************/ +LSCSTATUS LSC_ReadLscInfo(uint8_t* state, uint16_t* version); + +/******************************************************************************* +** ** Function: Numof_lengthbytes ** ** Description: Checks the number of length bytes and assigns diff --git a/ls_client/src/LsClient.cpp b/ls_client/src/LsClient.cpp index 05a24ba..f7a78de 100755 --- a/ls_client/src/LsClient.cpp +++ b/ls_client/src/LsClient.cpp @@ -16,14 +16,19 @@ * ******************************************************************************/ #define LOG_TAG "LSClient" -#include "LsClient.h" + #include <cutils/properties.h> #include <dirent.h> +#include <errno.h> #include <log/log.h> #include <openssl/evp.h> #include <pthread.h> #include <stdlib.h> +#include <iomanip> +#include <sstream> #include <string> + +#include "LsClient.h" #include "LsLib.h" uint8_t datahex(char c); @@ -41,9 +46,78 @@ 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; +class LSInfo { + public: + uint8_t m_status; + uint8_t m_version; + uint8_t m_mode; + uint8_t m_slot1_status; + uint8_t m_slot1_hash; + uint8_t m_slot2_status; + uint8_t m_slot2_hash; +}; + +static LSC_onCompletedCallback mCallback = nullptr; +static void* mCallbackParams = NULL; + void* performLSDownload_thread(void* data); static void getLSScriptSourcePrefix(std::string& prefix); +static int compareLSHash(uint8_t* hash, uint8_t length); +static std::string printLSStatus(int status); +static std::string dumpLsInfo(LSInfo* info); + +static int compareLSHash(uint8_t* hash, uint8_t length) { + uint8_t ls253UpdaterScriptHash[HASH_DATA_LENGTH - 1] = { + 0x65, 0x80, 0xFB, 0xA0, 0xCA, 0x59, 0xAE, 0x6C, 0x71, 0x6B, + 0x15, 0xB1, 0xBD, 0xB1, 0x2C, 0x04, 0x29, 0x14, 0x8A, 0x8F}; + uint8_t ls253AppletScriptHash[HASH_DATA_LENGTH - 1] = { + 0x71, 0x7B, 0x8D, 0x0C, 0xEA, 0xE7, 0xEC, 0xC1, 0xCF, 0x47, + 0x33, 0x10, 0xFE, 0x8E, 0x52, 0x5D, 0xB1, 0x43, 0x9B, 0xDE}; + uint8_t lsFactoryScript1Hash[HASH_DATA_LENGTH - 1] = { + 0x4A, 0xD0, 0x37, 0xD0, 0x44, 0x5B, 0x78, 0x55, 0x17, 0x5E, + 0xFD, 0x87, 0x9C, 0xF1, 0x74, 0xBA, 0x77, 0xAD, 0x03, 0x62}; + uint8_t lsFactoryScript2Hash[HASH_DATA_LENGTH - 1] = { + 0xA9, 0xDB, 0x03, 0x53, 0xC2, 0xD7, 0xF8, 0xFC, 0x84, 0x37, + 0xAF, 0xB9, 0x53, 0x06, 0x27, 0x9D, 0xE9, 0x68, 0x45, 0xEF}; + uint8_t lsFactoryScript3Hash[HASH_DATA_LENGTH - 1] = { + 0xA9, 0xAE, 0x5E, 0x66, 0x92, 0x8F, 0x70, 0xBD, 0x0A, 0xC7, + 0x20, 0x8A, 0x6A, 0xBB, 0x63, 0xB3, 0xCA, 0x05, 0x58, 0xC1}; + uint8_t lsFactoryScript4Hash[HASH_DATA_LENGTH - 1] = { + 0x64, 0x73, 0x56, 0xAE, 0x58, 0x27, 0x6C, 0x07, 0x4B, 0xBA, + 0x64, 0x7E, 0x6E, 0xC1, 0x97, 0xC8, 0x57, 0x17, 0x6E, 0x2D}; + uint8_t* hashList[6] = {lsFactoryScript1Hash, lsFactoryScript2Hash, + lsFactoryScript3Hash, lsFactoryScript4Hash, + ls253UpdaterScriptHash, ls253AppletScriptHash}; + + if (length != HASH_DATA_LENGTH - 1) { + return 0xFF; + } + for (int i = 0; i < 6; i++) { + if (0 == memcmp(hash, hashList[i], length)) { + return i + 1; + } + } + return 0xFF; +} + +static std::string dumpLsInfo(LSInfo* info) { + std::stringstream buff; + buff << std::setw(2) << std::setfill('0') << std::hex + << (int)(info->m_status); + buff << std::setw(2) << std::setfill('0') << std::hex + << (int)(info->m_version); + buff << std::setw(2) << std::setfill('0') << std::hex + << (int)(info->m_mode); + buff << std::setw(2) << std::setfill('0') << std::hex + << (int)(info->m_slot1_status); + buff << std::setw(2) << std::setfill('0') << std::hex + << (int)(info->m_slot1_hash); + buff << std::setw(2) << std::setfill('0') << std::hex + << (int)(info->m_slot2_status); + buff << std::setw(2) << std::setfill('0') << std::hex + << (int)(info->m_slot2_hash); + return buff.str(); +} void getLSScriptSourcePrefix(std::string& prefix) { char source_path[PROPERTY_VALUE_MAX] = {0}; @@ -92,20 +166,22 @@ LSCSTATUS LSC_Start(const char* name, const char* dest, uint8_t* pdata, ** ** Function: LSC_doDownload ** -** Description: Start LS download process by creating thread +** Description: Start LS download process ** -** Returns: SUCCESS of ok +** Returns: SUCCESS if ok ** *******************************************************************************/ -LSCSTATUS LSC_doDownload( - const android::sp<ISecureElementHalCallback>& clientCallback) { +LSCSTATUS LSC_doDownload(LSC_onCompletedCallback callback, void* args) { static const char fn[] = "LSC_doDownload"; + + mCallback = callback; + mCallbackParams = args; + 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; @@ -118,6 +194,98 @@ LSCSTATUS LSC_doDownload( /******************************************************************************* ** +** Function: printLSStatus +** +** Description: print LS applet state and Slot 1 & 2 data +** +** Returns: LS status log +** +*******************************************************************************/ +std::string printLSStatus(int lsStatus) { + ALOGD_IF(ese_debug_enabled, "%s enter ", __func__); + + uint8_t slotHashBuffer[HASH_DATA_LENGTH] = {0}; + uint16_t length = 0; + uint16_t lsVersion = 0; + uint8_t lsMode = 0; + std::stringstream outStream; + std::stringstream outHash; + + LSInfo lsInfo; + memset(&lsInfo, 0xFF, sizeof(LSInfo)); + lsInfo.m_status = lsStatus; + + outStream << "\nCurrent LS info:"; + /*Read LS applet mode*/ + LSCSTATUS status = LSC_ReadLscInfo(&lsMode, &lsVersion); + if (status != LSCSTATUS_SUCCESS) { + outStream << dumpLsInfo(&lsInfo); + outStream << "\nFailed to access LS applet!\n"; + return outStream.str(); + } + + ALOGI_IF(ese_debug_enabled, "LS applet version is %d.%d", (lsVersion >> 8), + (lsVersion & 0xFF)); + if (lsMode == 2) { + ALOGI_IF(ese_debug_enabled, "LS is in UPDATE mode!"); + } + lsInfo.m_version = lsVersion & 0xFF; + lsInfo.m_mode = lsMode; + + /*Read the hash from slot 1*/ + status = LSC_ReadLsHash(slotHashBuffer, &length, 1); + if (status != LSCSTATUS_SUCCESS) { + ALOGI_IF(ese_debug_enabled, "Failed to read Hash value from slot 1."); + outStream << dumpLsInfo(&lsInfo); + return outStream.str(); + } + if (slotHashBuffer[HASH_DATA_LENGTH - 1] == LS_DOWNLOAD_SUCCESS) { + ALOGI_IF(ese_debug_enabled, "LS Slot 1 passed."); + lsInfo.m_slot1_status = LS_DOWNLOAD_SUCCESS; + } else { + ALOGI_IF(ese_debug_enabled, "LS Slot 1 failed."); + lsInfo.m_slot1_status = LS_DOWNLOAD_FAILED; + } + lsInfo.m_slot1_hash = compareLSHash(slotHashBuffer, HASH_DATA_LENGTH - 1); + if (lsInfo.m_slot1_hash == 0xFF) { + outHash << "\n slot 1 hash:\n"; + for (int i = 0; i < HASH_DATA_LENGTH - 1; i++) { + outHash << std::setw(2) << std::setfill('0') << std::hex + << (int)slotHashBuffer[i]; + } + } + + /*Read the hash from slot 2*/ + status = LSC_ReadLsHash(slotHashBuffer, &length, 2); + if (status != LSCSTATUS_SUCCESS) { + ALOGI_IF(ese_debug_enabled, "Failed to read Hash value from slot 1."); + outStream << dumpLsInfo(&lsInfo); + return outStream.str(); + } + if (slotHashBuffer[HASH_DATA_LENGTH - 1] == LS_DOWNLOAD_SUCCESS) { + ALOGI_IF(ese_debug_enabled, "LS Slot 2 passed."); + lsInfo.m_slot2_status = LS_DOWNLOAD_SUCCESS; + } else { + ALOGI_IF(ese_debug_enabled, "LS Slot 2 failed."); + lsInfo.m_slot2_status = LS_DOWNLOAD_FAILED; + } + lsInfo.m_slot2_hash = compareLSHash(slotHashBuffer, HASH_DATA_LENGTH - 1); + if (lsInfo.m_slot2_hash == 0xFF) { + outHash << "\n slot 2 hash:\n"; + for (int i = 0; i < HASH_DATA_LENGTH - 1; i++) { + outHash << std::setw(2) << std::setfill('0') << std::hex + << (int)slotHashBuffer[i]; + } + } + + outStream << dumpLsInfo(&lsInfo) << outHash.str(); + + ALOGD_IF(ese_debug_enabled, "%s exit\n", __func__); + return outStream.str(); +} + +/******************************************************************************* +** ** Function: performLSDownload_thread ** ** Description: Perform LS during hal init @@ -154,8 +322,8 @@ void* performLSDownload_thread(__attribute__((unused)) void* data) { 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)); + ALOGE("%s Cannot open LS script file %s, Error: %s\n", __func__, + sourcePath.c_str(), strerror(errno)); break; } ALOGD_IF(ese_debug_enabled, "%s File opened %s\n", __func__, @@ -236,8 +404,11 @@ void* performLSDownload_thread(__attribute__((unused)) void* data) { } else { ALOGE("%s: Ese_deInit failed", __func__); } - cCallback->onStateChange(false); - break; + + if (mCallback != nullptr) { + (mCallback)(false, printLSStatus(LS_DOWNLOAD_FAILED), mCallbackParams); + break; + } } else { /*If current script execution is succes, update the status along with the * hash to the applet*/ @@ -253,7 +424,9 @@ void* performLSDownload_thread(__attribute__((unused)) void* data) { phNxpEse_free(lsHashInfo.readBuffHash); if (status == LSCSTATUS_SUCCESS) { - cCallback->onStateChange(true); + if (mCallback != nullptr) { + (mCallback)(true, printLSStatus(LS_DOWNLOAD_SUCCESS), mCallbackParams); + } } pthread_exit(NULL); ALOGD_IF(ese_debug_enabled, "%s pthread_exit\n", __func__); diff --git a/ls_client/src/LsLib.cpp b/ls_client/src/LsLib.cpp index 9dac201..82f64f0 100755 --- a/ls_client/src/LsLib.cpp +++ b/ls_client/src/LsLib.cpp @@ -2130,3 +2130,57 @@ LSCSTATUS LSC_UpdateLsHash(uint8_t* hash, long hashLen, uint8_t slotId) { phNxpEse_free(rspApdu.p_data); return lsStatus; } + +/******************************************************************************* +** +** Function: LSC_ReadLscInfo +** +** Description: Read the state of LS applet +** +** Returns: SUCCESS/FAILURE +** +*******************************************************************************/ +LSCSTATUS LSC_ReadLscInfo(uint8_t* state, uint16_t* version) { + static const char fn[] = "LSC_ReadLscInfo"; + phNxpEse_data cmdApdu; + phNxpEse_data rspApdu; + LSCSTATUS status = LSCSTATUS_FAILED; + ALOGD_IF(ese_debug_enabled, "%s: Enter ", __func__); + + phNxpEse_memset(&cmdApdu, 0x00, sizeof(phNxpEse_data)); + phNxpEse_memset(&rspApdu, 0x00, sizeof(phNxpEse_data)); + + /*p_data will have channel_id (1 byte) + SelectLsc APDU*/ + cmdApdu.len = (int32_t)(sizeof(SelectLsc) + 1); + cmdApdu.p_data = (uint8_t*)phNxpEse_memalloc(cmdApdu.len * sizeof(uint8_t)); + cmdApdu.p_data[0] = 0x00; // fchannel 0 + + memcpy(&(cmdApdu.p_data[1]), SelectLsc, sizeof(SelectLsc)); + + ALOGD_IF(ese_debug_enabled, "%s: Selecting Loader service applet", 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))) { + 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); + } else { + *state = rspApdu.p_data[18]; + *version = (rspApdu.p_data[22] << 8) | rspApdu.p_data[23]; + } + } else if (rspApdu.p_data[rspApdu.len - 2] != 0x90) { + ALOGE("%s: Selecting Loader service applet failed", fn); + status = LSCSTATUS_FAILED; + } + + ALOGD_IF(ese_debug_enabled, "%s: Exit ", __func__); + phNxpEse_free(cmdApdu.p_data); + phNxpEse_free(rspApdu.p_data); + return status; +} |