Files
hardware_interfaces/secure_element/aidl/default/main.cpp
Henri Chataing 4b780ebe46 secure_element: Fix the expectation for closeChannel in VTS tests
The AIDL interface states that closeChannel must return FAILED
if the channel is not opened. The default AIDL implementation
did not respect this requirement either.

Bug: 266384111
Test: m VtsHalSecureElementTargetTest
Change-Id: I3e7142e6bbeb9d79cea2c109689da59c0615167a
2023-02-02 16:20:42 +00:00

717 lines
29 KiB
C++

/*
* Copyright (C) 2022 The Android Open Source Project
*
* 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.
*/
#include <aidl/android/hardware/secure_element/BnSecureElement.h>
#include <android-base/hex.h>
#include <android-base/logging.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include <algorithm>
using aidl::android::hardware::secure_element::BnSecureElement;
using aidl::android::hardware::secure_element::ISecureElementCallback;
using aidl::android::hardware::secure_element::LogicalChannelResponse;
using android::base::HexString;
using ndk::ScopedAStatus;
static const std::vector<uint8_t> kIssuerSecurityDomainSelectResponse = {0x00, 0x00, 0x90, 0x00};
namespace se {
// Application identifier.
using Aid = std::vector<uint8_t>;
// ISO7816 APDU status codes.
enum Status : uint16_t {
SW_WRONG_DATA = 0x6A80,
SW_LOGICAL_CHANNEL_NOT_SUPPORTED = 0x6881,
SW_CONDITIONS_NOT_SATISFIED = 0x6985,
SW_INCORRECT_P1P2 = 0x6A86,
SW_BYTES_REMAINING_00 = 0x6100,
SW_WRONG_LENGTH = 0x6700,
SW_CORRECT_LENGTH_00 = 0x6C00,
SW_INS_NOT_SUPPORTED = 0x6D00,
SW_NO_ERROR = 0x9000,
};
// Type for raw APDUs.
using RawApdu = std::vector<uint8_t>;
// Wrap a command APDU (Application Processing Data Unit) to provide
// accessors for header fields.
struct Apdu {
public:
// Construct a command Apdu.
Apdu(std::vector<uint8_t> packet) : bytes_(std::move(packet)) {
CHECK(bytes_.size() >= kHeaderSize) << "command APDU created with invalid length";
size_t payload_len = bytes_.size() - kHeaderSize;
// TODO(b/123254068) - add support for extended command APDUs.
// Pre compute Lc and Le.
// Case 1: CLA | INS | P1 | P2
if (payload_len == 0) {
lc_ = 0;
le_ = 0;
return;
}
// Case 2: CLA | INS | P1 | P2 | Le
// Le has a value of 1 to 255.
if (payload_len == 1) {
le_ = bytes_[kHeaderSize];
le_ = le_ == 0 ? 256 : le_;
lc_ = 0;
return;
}
// Case 3: CLA | INS | P1 | P2 | Lc | Data
// Lc is less than 256 bytes
// of data, and Le is zero.
lc_ = bytes_[kHeaderSize];
if (payload_len <= (1 + lc_)) {
le_ = 0;
}
// Case 4: CLA | INS | P1 | P2 | Lc | Data | Le
// The legacy Case 4. Lc and Le
// are less than 256 bytes of data.
else {
le_ = bytes_[bytes_.size() - 1];
le_ = le_ == 0 ? 256 : le_;
}
}
// Construct a response Apdu with data.
static RawApdu CreateResponse(std::vector<uint8_t> data, Status status) {
// Append status word.
data.push_back(status >> 8);
data.push_back(status);
return data;
}
// Construct a response Apdu with no data.
static RawApdu CreateResponse(Status status) {
// Append status word.
return std::vector<uint8_t>{static_cast<uint8_t>(status >> 8),
static_cast<uint8_t>(status)};
}
// Return if command APDU is extended.
// The ISO/IEC 7816-4:2013 specification defines an extended APDU as any APDU
// whose payload data, response data or expected data length exceeds the 256
// byte limit.
bool IsExtended() const { return (bytes_.size() - kHeaderSize) > 256; }
// Return if command APDU has payload bytes.
bool HasPayload() const { return bytes_.size() > kHeaderSize; }
uint8_t get_cla() const { return bytes_[0]; }
uint8_t get_ins() const { return bytes_[1]; }
uint8_t get_p1() const { return bytes_[2]; }
uint8_t get_p2() const { return bytes_[3]; }
// Return the channel number encoded in the CLA field.
uint8_t get_channel_number() const {
// Type 4 commands — Encode legacy ISO/IEC 7816-4 logical channel
// information. Type 16 commands — Defined by the ISO/IEC 7816-4:2013
// specification to
// encode information for additional 16 logical channels in the card.
uint8_t cla = get_cla();
return (cla & 0x40) == 0 ? cla & 0x3 : 4 + (cla & 0xf);
}
// Return the length of the command data field.
uint16_t get_lc() const { return lc_; }
// Return the expected length of the response data field.
// Le should be have the same format as Lc.
uint16_t get_le() const { return le_; }
// Get the pointer to the APDU raw data.
std::vector<uint8_t> const& get_data() const { return bytes_; }
private:
// Size of command header, including CLA, INS, P1, P2 fields.
const size_t kHeaderSize = 4;
// Command or response buffer.
std::vector<uint8_t> bytes_{};
// Lengths of command data field and expected response data field.
uint16_t lc_{0};
uint16_t le_{0};
};
// Type of SE applets.
class Applet {
public:
virtual ~Applet() {}
// Called to inform this applet that it has been selected.
virtual RawApdu Select(Aid const& aid, uint8_t p2) = 0;
// Called by the Java Card runtime environment to process an
// incoming APDU command. SELECT commands are processed by \ref select
// instead.
virtual RawApdu Process(Apdu const& apdu) = 0;
};
}; // namespace se
// Implement the Google-eSE-test.cap test applet for passing OMAPI CTS tests
// on Cuttlefish. The reference can be found here:
// cts/tests/tests/secure_element/sample_applet/src/com/android/cts/omapi/test/CtsAndroidOmapiTestApplet.java
class CtsAndroidOmapiTestApplet : public se::Applet {
public:
CtsAndroidOmapiTestApplet() {}
virtual ~CtsAndroidOmapiTestApplet() {}
se::RawApdu Select(se::Aid const& aid, uint8_t /*p2*/) override {
if (aid[aid.size() - 1] == 0x31) {
// AID: A000000476416E64726F696443545331
return se::Apdu::CreateResponse(se::Status::SW_NO_ERROR);
} else {
// AID: A000000476416E64726F696443545332
return se::Apdu::CreateResponse(GenerateBerTLVBytes(SELECT_RESPONSE_DATA_LENGTH),
se::Status::SW_NO_ERROR);
}
}
se::RawApdu ReadNextResponseChunk(uint16_t max_output_len) {
uint16_t output_len = static_cast<uint16_t>(response_.size() - response_offset_);
output_len = std::min<uint16_t>(max_output_len, output_len);
std::vector<uint8_t> output{
&response_[response_offset_],
&response_[response_offset_ + output_len],
};
response_offset_ += output_len;
uint16_t remaining_len = response_.size() - response_offset_;
se::Status status = se::Status::SW_NO_ERROR;
if (remaining_len > 0) {
if (remaining_len > 256) {
remaining_len = 0x00;
}
status = se::Status(se::Status::SW_BYTES_REMAINING_00 | remaining_len);
} else {
response_.clear();
response_offset_ = 0;
}
return se::Apdu::CreateResponse(output, status);
}
se::RawApdu Process(se::Apdu const& apdu) override {
uint16_t lc;
uint16_t le = apdu.get_le();
uint8_t p1 = apdu.get_p1();
uint8_t p2 = apdu.get_p2();
switch (apdu.get_ins()) {
case NO_DATA_INS_1:
case NO_DATA_INS_2:
LOG(INFO) << __func__ << ": NO_DATA_INS_1|2";
return se::Apdu::CreateResponse(se::Status::SW_NO_ERROR);
case DATA_INS_1:
case DATA_INS_2:
// Return 256 bytes of data.
LOG(INFO) << __func__ << ": DATA_INS_1|2";
return se::Apdu::CreateResponse(GeneratesBytes(256), se::Status::SW_NO_ERROR);
case GET_RESPONSE_INS:
// ISO GET_RESPONSE command.
LOG(INFO) << __func__ << ": GET_RESPONSE_INS";
if (response_.empty()) {
return se::Apdu::CreateResponse(se::Status::SW_CONDITIONS_NOT_SATISFIED);
}
return ReadNextResponseChunk(apdu.get_le());
case SW_62xx_APDU_INS:
LOG(INFO) << __func__ << ": SW_62xx_APDU_INS";
if (p1 < 1 || p1 > 16) {
return se::Apdu::CreateResponse(se::Status::SW_INCORRECT_P1P2);
}
if (p2 == SW_62xx_DATA_APDU_P2) {
return se::Apdu::CreateResponse(GeneratesBytes(3),
se::Status(SW_62xx_resp[p1 - 1]));
}
if (p2 == SW_62xx_VALIDATE_DATA_P2) {
std::vector<uint8_t> output{SW_62xx_VALIDATE_DATA_RESP.begin(),
SW_62xx_VALIDATE_DATA_RESP.end()};
output[2] = p1;
return se::Apdu::CreateResponse(std::move(output),
se::Status(SW_62xx_resp[p1 - 1]));
}
return se::Apdu::CreateResponse(se::Status(SW_62xx_resp[p1 - 1]));
case SEGMENTED_RESP_INS_1:
case SEGMENTED_RESP_INS_2:
LOG(INFO) << __func__ << ": SEGMENTED_RESP_INS_1|2";
response_ = GeneratesBytes((static_cast<uint16_t>(p1) << 8) | p2);
response_offset_ = 0;
return ReadNextResponseChunk(std::min<uint16_t>(apdu.get_le(), 256));
case SEGMENTED_RESP_INS_3:
case SEGMENTED_RESP_INS_4:
LOG(INFO) << __func__ << ": SEGMENTED_RESP_INS_3|4";
response_ = GeneratesBytes((static_cast<uint16_t>(p1) << 8) | p2);
response_offset_ = 0;
return ReadNextResponseChunk(apdu.get_le());
case SEGMENTED_RESP_INS_5:
LOG(INFO) << __func__ << ": SEGMENTED_RESP_INS_5";
if (le == 0xff) {
return se::Apdu::CreateResponse(
se::Status(se::Status::SW_CORRECT_LENGTH_00 | 0xff));
}
response_ = GeneratesBytes((static_cast<uint16_t>(p1) << 8) | p2);
response_offset_ = 0;
return ReadNextResponseChunk(apdu.get_le());
case CHECK_SELECT_P2_APDU:
LOG(INFO) << __func__ << ": CHECK_SELECT_P2_APDU";
return se::Apdu::CreateResponse(std::vector<uint8_t>{apdu.get_p2()},
se::Status::SW_NO_ERROR);
default:
// Case is not known.
LOG(INFO) << __func__ << ": UNKNOWN_INS";
return se::Apdu::CreateResponse(se::Status::SW_INS_NOT_SUPPORTED);
}
}
private:
std::vector<uint8_t> response_{};
uint16_t response_offset_{0};
static const uint8_t NO_DATA_INS_1 = 0x06;
static const uint8_t NO_DATA_INS_2 = 0x0A;
static const uint8_t DATA_INS_1 = 0x08;
static const uint8_t DATA_INS_2 = 0x0C;
static const uint8_t SW_62xx_APDU_INS = 0xF3;
static const uint8_t SW_62xx_DATA_APDU_P2 = 0x08;
static const uint8_t SW_62xx_VALIDATE_DATA_P2 = 0x0C;
static constexpr std::array<uint8_t, 7> SW_62xx_VALIDATE_DATA_RESP = {0x01, 0xF3, 0x00, 0x0C,
0x01, 0xAA, 0x00};
static constexpr uint16_t SW_62xx_resp[] = {
0x6200, 0x6281, 0x6282, 0x6283, 0x6285, 0x62F1, 0x62F2, 0x63F1,
0x63F2, 0x63C2, 0x6202, 0x6280, 0x6284, 0x6286, 0x6300, 0x6381,
};
static const uint8_t SEGMENTED_RESP_INS_1 = 0xC2;
static const uint8_t SEGMENTED_RESP_INS_2 = 0xC4;
static const uint8_t SEGMENTED_RESP_INS_3 = 0xC6;
static const uint8_t SEGMENTED_RESP_INS_4 = 0xC8;
static const uint8_t SEGMENTED_RESP_INS_5 = 0xCF;
static const uint8_t CHECK_SELECT_P2_APDU = 0xF4;
static const uint8_t GET_RESPONSE_INS = 0xC0;
static const uint8_t BER_TLV_TYPE = 0x1F;
static const uint16_t SELECT_RESPONSE_DATA_LENGTH = 252;
static const uint16_t LENGTH_256 = 0x0100;
static constexpr std::array<uint8_t, 256> resp_bytes256{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B,
0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,
0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53,
0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61,
0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D,
0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B,
0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5,
0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3,
0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1,
0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED,
0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB,
0xFC, 0xFD, 0xFE, 0xFF};
// Generate a response buffer of the selected length containing valid
// BER TLV bytes.
static std::vector<uint8_t> GenerateBerTLVBytes(uint16_t le) {
// Support length from 0x00 - 0x7FFF.
uint16_t le_len = 1;
if (le < (uint16_t)0x80) {
le_len = 1;
} else if (le < (uint16_t)0x100) {
le_len = 2;
} else {
le_len = 3;
}
uint16_t total_len = (uint16_t)(le + 2 + le_len);
std::vector<uint8_t> output(total_len);
uint16_t i = 0;
output[i++] = BER_TLV_TYPE;
output[i++] = 0x00; // second byte of Type
if (le < 0x80) {
output[i++] = le;
} else if (le < 0x100) {
output[i++] = 0x81;
output[i++] = le;
} else {
output[i++] = 0x82;
output[i++] = (le >> 8);
output[i++] = (le & 0xFF);
}
while (i < total_len) {
output[i++] = ((i - 2 - le_len) & 0xFF);
}
// Set the last byte to 0xFF for CTS validation.
output[total_len - 1] = 0xFF;
return output;
}
// Generate a response buffer of the selected length using the
// array resp_bytes256 as input.
static std::vector<uint8_t> GeneratesBytes(uint16_t total_len) {
std::vector<uint8_t> output(total_len);
uint16_t i = 0;
while (i < total_len) {
if ((total_len - i) >= resp_bytes256.size()) {
std::memcpy(&output[i], resp_bytes256.data(), resp_bytes256.size());
i += resp_bytes256.size();
} else {
output[i] = i & 0xFF;
i += 1;
}
}
// Set the last byte to 0xFF for CTS validation.
output[total_len - 1] = 0xFF;
return output;
}
};
class EmulatedSecureElement : public BnSecureElement {
public:
EmulatedSecureElement() {
std::shared_ptr<CtsAndroidOmapiTestApplet> test_applet =
std::make_shared<CtsAndroidOmapiTestApplet>();
applets_.push_back(std::pair{se::Aid{0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64, 0x72,
0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x31},
test_applet});
applets_.push_back(std::pair{se::Aid{0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64, 0x72,
0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x32},
test_applet});
}
ScopedAStatus init(const std::shared_ptr<ISecureElementCallback>& client_callback) override {
LOG(INFO) << __func__ << " callback: " << client_callback.get();
if (client_callback == nullptr) {
return ScopedAStatus::fromExceptionCode(EX_NULL_POINTER);
}
for (auto& channel : channels_) {
channel = Channel();
}
client_callback_ = client_callback;
client_callback_->onStateChange(true, "init");
return ScopedAStatus::ok();
}
ScopedAStatus getAtr(std::vector<uint8_t>* aidl_return) override {
LOG(INFO) << __func__;
if (client_callback_ == nullptr) {
return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
*aidl_return = atr_;
return ScopedAStatus::ok();
}
ScopedAStatus reset() override {
LOG(INFO) << __func__;
if (client_callback_ == nullptr) {
return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
client_callback_->onStateChange(false, "reset");
client_callback_->onStateChange(true, "reset");
// All channels are closed after reset.
for (auto& channel : channels_) {
channel = Channel();
}
return ScopedAStatus::ok();
}
ScopedAStatus isCardPresent(bool* aidl_return) override {
LOG(INFO) << __func__;
if (client_callback_ == nullptr) {
return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
*aidl_return = true;
return ScopedAStatus::ok();
}
ScopedAStatus openBasicChannel(const std::vector<uint8_t>& aid, int8_t p2,
std::vector<uint8_t>* aidl_return) override {
LOG(INFO) << __func__ << " aid: " << HexString(aid.data(), aid.size()) << " (" << aid.size()
<< ") p2 " << p2;
if (client_callback_ == nullptr) {
return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
std::vector<uint8_t> select_response;
std::shared_ptr<se::Applet> applet = nullptr;
// The basic channel can only be opened once, and stays opened
// and locked until the channel is closed.
if (channels_[0].opened) {
LOG(INFO) << __func__ << " basic channel already opened";
return ScopedAStatus::fromServiceSpecificError(CHANNEL_NOT_AVAILABLE);
}
// If the AID is defined (the AID is not Null and the length of the
// AID is not 0) and the channel is not locked then the corresponding
// applet shall be selected.
if (aid.size() > 0) {
applet = SelectApplet(aid);
if (applet == nullptr) {
// No applet registered with matching AID.
LOG(INFO) << __func__ << " basic channel AID not found";
return ScopedAStatus::fromServiceSpecificError(NO_SUCH_ELEMENT_ERROR);
}
select_response = applet->Select(aid, p2);
}
// If the AID is a 0 length AID and the channel is not locked, the
// method will select the Issuer Security Domain of the SE by sending a
// SELECT command with a 0 length AID as defined in
// [GP Card specification].
if (aid.size() == 0) {
select_response = kIssuerSecurityDomainSelectResponse;
}
LOG(INFO) << __func__ << " sending response: "
<< HexString(select_response.data(), select_response.size());
// TODO(b/123254068) - this is not an implementation of the OMAPI protocol
// or APDU. The functionality here is enough to exercise the framework,
// but actual calls to the secure element will fail. This implementation
// does not model channel isolation or any other aspects important to
// implementing secure element.
channels_[0] = Channel(aid, p2, applet);
*aidl_return = select_response;
return ScopedAStatus::ok();
}
ScopedAStatus openLogicalChannel(
const std::vector<uint8_t>& aid, int8_t p2,
::aidl::android::hardware::secure_element::LogicalChannelResponse* aidl_return)
override {
LOG(INFO) << __func__ << " aid: " << HexString(aid.data(), aid.size()) << " (" << aid.size()
<< ") p2 " << p2;
if (client_callback_ == nullptr) {
return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
size_t channel_number = 1;
std::vector<uint8_t> select_response;
std::shared_ptr<se::Applet> applet = nullptr;
// Look for an available channel number.
for (; channel_number < channels_.size(); channel_number++) {
if (channels_[channel_number].opened == false) {
break;
}
}
// All channels are currently allocated.
if (channel_number >= channels_.size()) {
LOG(INFO) << __func__ << " all logical channels already opened";
return ScopedAStatus::fromServiceSpecificError(CHANNEL_NOT_AVAILABLE);
}
// If the AID is defined (the AID is not Null and the length of the
// AID is not 0) then the corresponding applet shall be selected.
if (aid.size() > 0) {
applet = SelectApplet(aid);
if (applet == nullptr) {
// No applet registered with matching AID.
LOG(INFO) << __func__ << " logical channel AID not found";
return ScopedAStatus::fromServiceSpecificError(NO_SUCH_ELEMENT_ERROR);
}
select_response = applet->Select(aid, p2);
}
// If the length of the AID is 0, the method will select the
// Issuer Security Domain of the SE by sending a SELECT command
// with 0 length AID as defined in [GPCS].
if (aid.size() == 0) {
select_response = kIssuerSecurityDomainSelectResponse;
}
LOG(INFO) << __func__ << " sending response: "
<< HexString(select_response.data(), select_response.size());
// TODO(b/123254068) - this is not an implementation of the OMAPI protocol
// or APDU. The functionality here is enough to exercise the framework,
// but actual calls to the secure element will fail. This implementation
// does not model channel isolation or any other aspects important to
// implementing secure element.
channels_[channel_number] = Channel(aid, p2, applet);
*aidl_return = LogicalChannelResponse{
.channelNumber = static_cast<int8_t>(channel_number),
.selectResponse = select_response,
};
return ScopedAStatus::ok();
}
ScopedAStatus closeChannel(int8_t channel_number) override {
LOG(INFO) << __func__ << " channel number: " << static_cast<int>(channel_number);
if (client_callback_ == nullptr) {
return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
// The selected basic or logical channel is not opened.
if (channel_number >= channels_.size() || !channels_[channel_number].opened) {
return ScopedAStatus::fromServiceSpecificError(FAILED);
}
// TODO(b/123254068) - this is not an implementation of the OMAPI protocol
// or APDU. The functionality here is enough to exercise the framework,
// but actual calls to the secure element will fail. This implementation
// does not model channel isolation or any other aspects important to
// implementing secure element.
channels_[channel_number].opened = false;
return ScopedAStatus::ok();
}
ScopedAStatus transmit(const std::vector<uint8_t>& data,
std::vector<uint8_t>* aidl_return) override {
LOG(INFO) << __func__ << " data: " << HexString(data.data(), data.size()) << " ("
<< data.size() << ")";
if (client_callback_ == nullptr) {
return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
se::Apdu apdu(data);
uint8_t channel_number = apdu.get_channel_number();
std::vector<uint8_t> response_apdu;
switch (apdu.get_ins()) {
// TODO(b/123254068) - Implement support channel management APDUs.
case MANAGE_CHANNEL_INS:
// P1 = '00' to open
// P1 = '80' to close
LOG(INFO) << __func__ << " MANAGE_CHANNEL apdu";
response_apdu =
se::Apdu::CreateResponse(se::Status::SW_LOGICAL_CHANNEL_NOT_SUPPORTED);
break;
// TODO(b/123254068) - Implement support channel management APDUs.
case SELECT_INS:
LOG(INFO) << __func__ << " SELECT apdu";
response_apdu =
se::Apdu::CreateResponse(se::Status::SW_LOGICAL_CHANNEL_NOT_SUPPORTED);
break;
default:
CHECK(channel_number < channels_.size()) << " invalid channel number";
if (!channels_[channel_number].opened) {
LOG(INFO) << __func__ << " the channel " << static_cast<int>(channel_number)
<< " is not opened";
response_apdu =
se::Apdu::CreateResponse(se::Status::SW_LOGICAL_CHANNEL_NOT_SUPPORTED);
break;
}
// Send the APDU to the applet for processing.
// Applet implementation is optional, default to sending
// SW_INS_NOT_SUPPORTED.
if (channels_[channel_number].applet == nullptr) {
response_apdu = se::Apdu::CreateResponse(se::Status::SW_INS_NOT_SUPPORTED);
} else {
response_apdu = channels_[channel_number].applet->Process(apdu);
}
break;
}
aidl_return->assign(response_apdu.begin(), response_apdu.end());
LOG(INFO) << __func__
<< " response: " << HexString(aidl_return->data(), aidl_return->size()) << " ("
<< aidl_return->size() << ")";
return ScopedAStatus::ok();
}
private:
struct Channel {
public:
Channel() = default;
Channel(Channel const&) = default;
Channel(se::Aid const& aid, uint8_t p2, std::shared_ptr<se::Applet> applet)
: opened(true), aid(aid), p2(p2), applet(std::move(applet)) {}
Channel& operator=(Channel const&) = default;
bool opened{false};
se::Aid aid{};
uint8_t p2{0};
std::shared_ptr<se::Applet> applet{nullptr};
};
// OMAPI abstraction.
// Channel 0 is the basic channel, channels 1-19 are the logical channels.
std::array<Channel, 20> channels_{};
std::shared_ptr<ISecureElementCallback> client_callback_{nullptr};
// Secure element abstraction.
static const uint8_t MANAGE_CHANNEL_INS = 0x70;
static const uint8_t SELECT_INS = 0xa4;
// Secure element ATR (Answer-To-Reset).
// The format is specified by ISO/IEC 1816-4 2020 and lists
// the capabilities of the card.
//
// TODO(b/123254068): encode the default SE properties in the ATR:
// support for extended Lc / Le fields, maximum number of logical channels.
// The CTS tests are *not* checking this value.
std::vector<uint8_t> const atr_{};
// Applet registration.
std::vector<std::pair<se::Aid, std::shared_ptr<se::Applet>>> applets_{};
// Return the first applet that matches the selected aid.
std::shared_ptr<se::Applet> SelectApplet(se::Aid const& aid) {
for (auto& [applet_aid, applet] : applets_) {
if (applet_aid == aid) {
return applet;
}
}
return nullptr;
}
};
int main() {
ABinderProcess_setThreadPoolMaxThreadCount(0);
auto se = ndk::SharedRefBase::make<EmulatedSecureElement>();
const std::string name = std::string() + BnSecureElement::descriptor + "/eSE1";
binder_status_t status = AServiceManager_addService(se->asBinder().get(), name.c_str());
CHECK_EQ(status, STATUS_OK);
ABinderProcess_joinThreadPool();
return EXIT_FAILURE; // should not reach
}