Merge changes from topic "OMAPI_VNTF"

* changes:
  replaced android.se.omapi-V1-ndk_platform library with android.se.omapi-V1-ndk
  VTS tests added for OMAPI Vendor stable interface
  Support for OMAPI Vendor stable interface
This commit is contained in:
Jack Yu
2021-11-23 04:54:02 +00:00
committed by Gerrit Code Review
23 changed files with 1459 additions and 17 deletions

View File

@@ -82,6 +82,7 @@ filegroup {
":framework-mca-filterpacks-sources",
":framework-media-sources",
":framework-mms-sources",
":framework-omapi-sources",
":framework-opengl-sources",
":framework-rs-sources",
":framework-sax-sources",
@@ -268,6 +269,7 @@ java_library {
"android.hardware.vibrator-V1.2-java",
"android.hardware.vibrator-V1.3-java",
"android.hardware.vibrator-V2-java",
"android.se.omapi-V1-java",
"android.system.suspend.control.internal-java",
"devicepolicyprotosnano",

35
omapi/aidl/Android.bp Normal file
View File

@@ -0,0 +1,35 @@
// Copyright 2020, 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.
package {
default_applicable_licenses: ["Android-Apache-2.0"],
}
aidl_interface {
name: "android.se.omapi",
vendor_available: true,
srcs: ["android/se/omapi/*.aidl"],
stability: "vintf",
backend: {
java: {
sdk_version: "module_current",
},
rust: {
enabled: true,
},
ndk: {
separate_platform_variant: false,
},
},
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright (C) 2021, 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.
*//*
* Contributed by: Giesecke & Devrient GmbH.
*/
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
// two cases:
// 1). this is a frozen version file - do not edit this in any case.
// 2). this is a 'current' file. If you make a backwards compatible change to
// the interface (from the latest frozen version), the build system will
// prompt you to update this file with `m <name>-update-api`.
//
// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.se.omapi;
/* @hide */
@VintfStability
interface ISecureElementChannel {
void close();
boolean isClosed();
boolean isBasicChannel();
byte[] getSelectResponse();
byte[] transmit(in byte[] command);
boolean selectNext();
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright (C) 2017, 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.
*//*
* Contributed by: Giesecke & Devrient GmbH.
*/
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
// two cases:
// 1). this is a frozen version file - do not edit this in any case.
// 2). this is a 'current' file. If you make a backwards compatible change to
// the interface (from the latest frozen version), the build system will
// prompt you to update this file with `m <name>-update-api`.
//
// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.se.omapi;
/* @hide */
@VintfStability
interface ISecureElementListener {
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright (C) 2017, 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.
*//*
* Contributed by: Giesecke & Devrient GmbH.
*/
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
// two cases:
// 1). this is a frozen version file - do not edit this in any case.
// 2). this is a 'current' file. If you make a backwards compatible change to
// the interface (from the latest frozen version), the build system will
// prompt you to update this file with `m <name>-update-api`.
//
// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.se.omapi;
/* @hide */
@VintfStability
interface ISecureElementReader {
boolean isSecureElementPresent();
android.se.omapi.ISecureElementSession openSession();
void closeSessions();
boolean reset();
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright (C) 2017, 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.
*//*
* Copyright (c) 2015-2017, The Linux Foundation.
*//*
* Contributed by: Giesecke & Devrient GmbH.
*/
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
// two cases:
// 1). this is a frozen version file - do not edit this in any case.
// 2). this is a 'current' file. If you make a backwards compatible change to
// the interface (from the latest frozen version), the build system will
// prompt you to update this file with `m <name>-update-api`.
//
// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.se.omapi;
/* @hide */
@VintfStability
interface ISecureElementService {
String[] getReaders();
android.se.omapi.ISecureElementReader getReader(in String reader);
boolean[] isNFCEventAllowed(in String reader, in byte[] aid, in String[] packageNames);
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright (C) 2017, 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.
*//*
* Copyright (c) 2015-2017, The Linux Foundation.
*//*
* Contributed by: Giesecke & Devrient GmbH.
*/
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
// two cases:
// 1). this is a frozen version file - do not edit this in any case.
// 2). this is a 'current' file. If you make a backwards compatible change to
// the interface (from the latest frozen version), the build system will
// prompt you to update this file with `m <name>-update-api`.
//
// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.se.omapi;
/* @hide */
@VintfStability
interface ISecureElementSession {
byte[] getAtr();
void close();
void closeChannels();
boolean isClosed();
android.se.omapi.ISecureElementChannel openBasicChannel(in byte[] aid, in byte p2, in android.se.omapi.ISecureElementListener listener);
android.se.omapi.ISecureElementChannel openLogicalChannel(in byte[] aid, in byte p2, in android.se.omapi.ISecureElementListener listener);
}

View File

@@ -22,6 +22,7 @@ package android.se.omapi;
import android.se.omapi.ISecureElementSession;
/** @hide */
@VintfStability
interface ISecureElementChannel {
/**
@@ -58,6 +59,9 @@ interface ISecureElementChannel {
* Transmits the specified command APDU and returns the response APDU.
* MANAGE channel commands are not supported.
* Selection of applets is not supported in logical channels.
*
* @param command Command APDU, its structure is defined in ISO/IEC 7816-4
* in Standard byte format
*/
byte[] transmit(in byte[] command);

View File

@@ -23,5 +23,6 @@ package android.se.omapi;
* Interface to receive call-backs when the service is connected.
* @hide
*/
@VintfStability
interface ISecureElementListener {
}

View File

@@ -22,6 +22,7 @@ package android.se.omapi;
import android.se.omapi.ISecureElementSession;
/** @hide */
@VintfStability
interface ISecureElementReader {
/**
@@ -34,7 +35,7 @@ interface ISecureElementReader {
* Connects to a secure element in this reader. <br>
* This method prepares (initialises) the Secure Element for communication
* before the Session object is returned (e.g. powers the Secure Element by
* ICC ON if its not already on). There might be multiple sessions opened at
* ICC ON if it is not already on). There might be multiple sessions opened at
* the same time on the same reader. The system ensures the interleaving of
* APDUs between the respective sessions.
*

View File

@@ -28,23 +28,31 @@ import android.se.omapi.ISecureElementReader;
* SecureElement service interface.
* @hide
*/
@VintfStability
interface ISecureElementService {
/**
* Returns the friendly names of available Secure Element readers.
* <ul>
* <li>If the reader is a SIM reader, then its name must be "SIM[Slot]".</li>
* <li>If the reader is a SD or micro SD reader, then its name must be "SD[Slot]"</li>
* <li>If the reader is a embedded SE reader, then its name must be "eSE[Slot]"</li>
* </ul>
* Slot is a decimal number without leading zeros. The Numbering must start with 1
* (e.g. SIM1, SIM2, ... or SD1, SD2, ... or eSE1, eSE2, ...).
*/
String[] getReaders();
/**
* Returns SecureElement Service reader object to the given name.
*/
ISecureElementReader getReader(String reader);
ISecureElementReader getReader(in String reader);
/**
* Checks if the application defined by the package name is allowed to
* receive NFC transaction events for the defined AID.
*/
boolean[] isNFCEventAllowed(String reader, in byte[] aid,
boolean[] isNFCEventAllowed(in String reader, in byte[] aid,
in String[] packageNames);
}

View File

@@ -27,6 +27,7 @@ import android.se.omapi.ISecureElementReader;
import android.se.omapi.ISecureElementListener;
/** @hide */
@VintfStability
interface ISecureElementSession {
/**
@@ -45,7 +46,6 @@ interface ISecureElementSession {
*/
void closeChannels();
/**
* Tells if this session is closed.
*
@@ -59,15 +59,19 @@ interface ISecureElementSession {
* applet if aid != null.
* Logical channels cannot be opened with this connection.
* Use interface method openLogicalChannel() to open a logical channel.
* Listener is passed to secure element service and used to monitor whether
* the client application that uses OMAPI is still alive or not.
*/
ISecureElementChannel openBasicChannel(in byte[] aid, in byte p2,
ISecureElementListener listener);
in ISecureElementListener listener);
/**
* Opens a connection using the next free logical channel of the card in the
* specified reader. Selects the specified applet.
* Selection of other applets with this connection is not supported.
* Listener is passed to secure element service and used to monitor whether
* the client application that uses OMAPI is still alive or not.
*/
ISecureElementChannel openLogicalChannel(in byte[] aid, in byte p2,
ISecureElementListener listener);
in ISecureElementListener listener);
}

View File

@@ -0,0 +1,54 @@
//
// Copyright (C) 2021 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.
//
package {
default_applicable_licenses: ["Android-Apache-2.0"],
}
cc_test {
name: "VtsHalOmapiSeAccessControlTestCases",
defaults: [
"VtsHalTargetTestDefaults",
"use_libaidlvintf_gtest_helper_static",
],
srcs: [
"VtsHalOmapiSeAccessControlTestCases.cpp",
],
shared_libs: [
"libbase",
"liblog",
"libcutils",
"libhidlbase",
"libnativehelper",
"libutils",
"libbinder_ndk",
],
static_libs: [
"VtsHalHidlTargetTestBase",
"android.se.omapi-V1-ndk",
],
cflags: [
"-O0",
"-g",
"-Wall",
"-Werror",
],
require_root: true,
test_suites: [
"general-tests",
"vts",
],
}

View File

@@ -0,0 +1,428 @@
/*
* Copyright (C) 2021 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/se/omapi/BnSecureElementListener.h>
#include <aidl/android/se/omapi/ISecureElementChannel.h>
#include <aidl/android/se/omapi/ISecureElementListener.h>
#include <aidl/android/se/omapi/ISecureElementReader.h>
#include <aidl/android/se/omapi/ISecureElementService.h>
#include <aidl/android/se/omapi/ISecureElementSession.h>
#include <VtsCoreUtil.h>
#include <aidl/Gtest.h>
#include <aidl/Vintf.h>
#include <android-base/logging.h>
#include <android/binder_manager.h>
#include <binder/IServiceManager.h>
#include <cutils/properties.h>
#include <gtest/gtest.h>
#include <hidl/GtestPrinter.h>
#include <hidl/ServiceManagement.h>
#include <utils/String16.h>
using namespace std;
using namespace ::testing;
using namespace android;
int main(int argc, char** argv) {
InitGoogleTest(&argc, argv);
int status = RUN_ALL_TESTS();
return status;
}
namespace {
class OMAPISEAccessControlTest : public TestWithParam<std::string> {
protected:
class SEListener : public ::aidl::android::se::omapi::BnSecureElementListener {};
/**
* Verifies TLV data
*
* @return true if the data is tlv formatted, false otherwise
*/
bool verifyBerTlvData(std::vector<uint8_t> tlv) {
if (tlv.size() == 0) {
LOG(ERROR) << "Invalid tlv, null";
return false;
}
int i = 0;
if ((tlv[i++] & 0x1F) == 0x1F) {
// extra byte for TAG field
i++;
}
int len = tlv[i++] & 0xFF;
if (len > 127) {
// more than 1 byte for length
int bytesLength = len - 128;
len = 0;
for (int j = bytesLength; j > 0; j--) {
len += (len << 8) + (tlv[i++] & 0xFF);
}
}
// Additional 2 bytes for the SW
return (tlv.size() == (i + len + 2));
}
void testSelectableAid(
std::vector<std::vector<uint8_t>> authorizedAids) {
for (auto aid : authorizedAids) {
std::shared_ptr<aidl::android::se::omapi::ISecureElementSession> session;
std::shared_ptr<aidl::android::se::omapi::ISecureElementChannel> channel;
auto seListener = ndk::SharedRefBase::make<SEListener>();
if (mVSReaders.size() > 0) {
for (const auto& [name, reader] : mVSReaders) {
std::vector<uint8_t> selectResponse = {};
ASSERT_NE(reader, nullptr) << "reader is null";
bool status = false;
auto res = reader->isSecureElementPresent(&status);
ASSERT_TRUE(res.isOk()) << res.getMessage();
ASSERT_TRUE(status);
res = reader->openSession(&session);
ASSERT_TRUE(res.isOk()) << res.getMessage();
ASSERT_NE(session, nullptr) << "Could not open session";
res = session->openLogicalChannel(aid, 0x00, seListener, &channel);
ASSERT_TRUE(res.isOk()) << res.getMessage();
ASSERT_NE(channel, nullptr) << "Could not open channel";
res = channel->getSelectResponse(&selectResponse);
ASSERT_TRUE(res.isOk()) << "failed to get Select Response";
ASSERT_GE(selectResponse.size(), 2);
if (channel != nullptr) channel->close();
if (session != nullptr) session->close();
ASSERT_EQ((selectResponse[selectResponse.size() - 1] & 0xFF), (0x00));
ASSERT_EQ((selectResponse[selectResponse.size() - 2] & 0xFF), (0x90));
ASSERT_TRUE(
verifyBerTlvData(selectResponse)) << "Select Response is not complete";
}
}
}
}
void testUnauthorisedAid(
std::vector<std::vector<uint8_t>> unAuthorizedAids) {
for (auto aid : unAuthorizedAids) {
std::shared_ptr<aidl::android::se::omapi::ISecureElementSession> session;
std::shared_ptr<aidl::android::se::omapi::ISecureElementChannel> channel;
auto seListener = ndk::SharedRefBase::make<SEListener>();
if (mVSReaders.size() > 0) {
for (const auto& [name, reader] : mVSReaders) {
ASSERT_NE(reader, nullptr) << "reader is null";
bool status = false;
auto res = reader->isSecureElementPresent(&status);
ASSERT_TRUE(res.isOk()) << res.getMessage();
ASSERT_TRUE(status);
res = reader->openSession(&session);
ASSERT_TRUE(res.isOk()) << res.getMessage();
ASSERT_NE(session, nullptr) << "Could not open session";
res = session->openLogicalChannel(aid, 0x00, seListener, &channel);
if (channel != nullptr) channel->close();
if (session != nullptr) session->close();
if (!res.isOk()) {
ASSERT_EQ(res.getExceptionCode(), EX_SECURITY);
ASSERT_FALSE(res.isOk()) << "expected failed status for this test";
}
}
}
}
}
void testTransmitAPDU(
std::vector<uint8_t> aid,
std::vector<std::vector<uint8_t>> apdus) {
for (auto apdu : apdus) {
std::shared_ptr<aidl::android::se::omapi::ISecureElementSession> session;
std::shared_ptr<aidl::android::se::omapi::ISecureElementChannel> channel;
auto seListener = ndk::SharedRefBase::make<SEListener>();
if (mVSReaders.size() > 0) {
for (const auto& [name, reader] : mVSReaders) {
ASSERT_NE(reader, nullptr) << "reader is null";
bool status = false;
std::vector<uint8_t> selectResponse = {};
std::vector<uint8_t> transmitResponse = {};
auto res = reader->isSecureElementPresent(&status);
ASSERT_TRUE(res.isOk()) << res.getMessage();
ASSERT_TRUE(status);
res = reader->openSession(&session);
ASSERT_TRUE(res.isOk()) << res.getMessage();
ASSERT_NE(session, nullptr) << "Could not open session";
res = session->openLogicalChannel(aid, 0x00, seListener, &channel);
ASSERT_TRUE(res.isOk()) << res.getMessage();
ASSERT_NE(channel, nullptr) << "Could not open channel";
res = channel->getSelectResponse(&selectResponse);
ASSERT_TRUE(res.isOk()) << "failed to get Select Response";
ASSERT_GE(selectResponse.size(), 2);
ASSERT_EQ((selectResponse[selectResponse.size() - 1] & 0xFF), (0x00));
ASSERT_EQ((selectResponse[selectResponse.size() - 2] & 0xFF), (0x90));
ASSERT_TRUE(
verifyBerTlvData(selectResponse)) << "Select Response is not complete";
res = channel->transmit(apdu, &transmitResponse);
LOG(INFO) << "STATUS OF TRNSMIT: " << res.getExceptionCode()
<< " Message: " << res.getMessage();
if (channel != nullptr) channel->close();
if (session != nullptr) session->close();
ASSERT_TRUE(res.isOk()) << "failed to transmit";
}
}
}
}
void testUnauthorisedAPDU(
std::vector<uint8_t> aid,
std::vector<std::vector<uint8_t>> apdus) {
for (auto apdu : apdus) {
std::shared_ptr<aidl::android::se::omapi::ISecureElementSession> session;
std::shared_ptr<aidl::android::se::omapi::ISecureElementChannel> channel;
auto seListener = ndk::SharedRefBase::make<SEListener>();
if (mVSReaders.size() > 0) {
for (const auto& [name, reader] : mVSReaders) {
ASSERT_NE(reader, nullptr) << "reader is null";
bool status = false;
std::vector<uint8_t> selectResponse = {};
std::vector<uint8_t> transmitResponse = {};
auto res = reader->isSecureElementPresent(&status);
ASSERT_TRUE(res.isOk()) << res.getMessage();
ASSERT_TRUE(status);
res = reader->openSession(&session);
ASSERT_TRUE(res.isOk()) << res.getMessage();
ASSERT_NE(session, nullptr) << "Could not open session";
res = session->openLogicalChannel(aid, 0x00, seListener, &channel);
ASSERT_TRUE(res.isOk()) << res.getMessage();
ASSERT_NE(channel, nullptr) << "Could not open channel";
res = channel->getSelectResponse(&selectResponse);
ASSERT_TRUE(res.isOk()) << "failed to get Select Response";
ASSERT_GE(selectResponse.size(), 2);
ASSERT_EQ((selectResponse[selectResponse.size() - 1] & 0xFF), (0x00));
ASSERT_EQ((selectResponse[selectResponse.size() - 2] & 0xFF), (0x90));
ASSERT_TRUE(
verifyBerTlvData(selectResponse)) << "Select Response is not complete";
res = channel->transmit(apdu, &transmitResponse);
LOG(INFO) << "STATUS OF TRNSMIT: " << res.getExceptionCode()
<< " Message: " << res.getMessage();
if (channel != nullptr) channel->close();
if (session != nullptr) session->close();
if (!res.isOk()) {
ASSERT_EQ(res.getExceptionCode(), EX_SECURITY);
ASSERT_FALSE(res.isOk()) << "expected failed status for this test";
}
}
}
}
}
bool supportOMAPIReaders() {
return (deviceSupportsFeature(FEATURE_SE_OMAPI_ESE.c_str()));
}
void getFirstApiLevel(int32_t* outApiLevel) {
int32_t firstApiLevel = property_get_int32(FEATURE_SE_API_LEVEL.c_str(), -1);
if (firstApiLevel < 0) {
firstApiLevel = property_get_int32(FEATURE_SE_SDK_VERSION.c_str(), -1);
}
ASSERT_GT(firstApiLevel, 0); // first_api_level must exist
*outApiLevel = firstApiLevel;
return;
}
bool supportsHardware() {
bool lowRamDevice = property_get_bool(FEATURE_SE_LOW_RAM.c_str(), true);
return !lowRamDevice || deviceSupportsFeature(FEATURE_SE_HARDWARE_WATCH.c_str()) ||
deviceSupportsFeature(FEATURE_SE_OMAPI_SERVICE.c_str()); // android.se.omapi
}
void SetUp() override {
ASSERT_TRUE(supportsHardware());
int32_t apiLevel;
getFirstApiLevel(&apiLevel);
ASSERT_TRUE(apiLevel > 27);
ASSERT_TRUE(supportOMAPIReaders());
LOG(INFO) << "get OMAPI service with name:" << GetParam();
::ndk::SpAIBinder ks2Binder(AServiceManager_getService(GetParam().c_str()));
mOmapiSeService = aidl::android::se::omapi::ISecureElementService::fromBinder(ks2Binder);
ASSERT_TRUE(mOmapiSeService);
std::vector<std::string> readers = {};
if (mOmapiSeService != NULL) {
auto status = mOmapiSeService->getReaders(&readers);
ASSERT_TRUE(status.isOk()) << status.getMessage();
for (auto readerName : readers) {
// Filter eSE readers only
if (readerName.find(ESE_READER_PREFIX, 0) != std::string::npos) {
std::shared_ptr<::aidl::android::se::omapi::ISecureElementReader> reader;
status = mOmapiSeService->getReader(readerName, &reader);
ASSERT_TRUE(status.isOk()) << status.getMessage();
mVSReaders[readerName] = reader;
}
}
}
}
void TearDown() override {
if (mOmapiSeService != nullptr) {
if (mVSReaders.size() > 0) {
for (const auto& [name, reader] : mVSReaders) {
reader->closeSessions();
}
}
}
}
static inline std::string const ESE_READER_PREFIX = "eSE";
static inline std::string const FEATURE_SE_OMAPI_ESE = "android.hardware.se.omapi.ese";
static inline std::string const FEATURE_SE_LOW_RAM = "ro.config.low_ram";
static inline std::string const FEATURE_SE_HARDWARE_WATCH = "android.hardware.type.watch";
static inline std::string const FEATURE_SE_OMAPI_SERVICE = "com.android.se";
static inline std::string const FEATURE_SE_SDK_VERSION = "ro.build.version.sdk";
static inline std::string const FEATURE_SE_API_LEVEL = "ro.product.first_api_level";
std::vector<uint8_t> AID_40 = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x40};
std::vector<uint8_t> AID_41 = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x41};
std::vector<uint8_t> AID_42 = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x42};
std::vector<uint8_t> AID_43 = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x43};
std::vector<uint8_t> AID_44 = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x44};
std::vector<uint8_t> AID_45 = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x45};
std::vector<uint8_t> AID_46 = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x46};
std::vector<uint8_t> AID_47 = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x47};
std::vector<uint8_t> AID_48 = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x48};
std::vector<uint8_t> AID_49 = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x49};
std::vector<uint8_t> AID_4A = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x4A};
std::vector<uint8_t> AID_4B = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x4B};
std::vector<uint8_t> AID_4C = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x4C};
std::vector<uint8_t> AID_4D = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x4D};
std::vector<uint8_t> AID_4E = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x4E};
std::vector<uint8_t> AID_4F = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x4F};
std::vector<std::vector<uint8_t>> AUTHORIZED_AID = {AID_40, AID_41, AID_42, AID_44, AID_45,
AID_47, AID_48, AID_49, AID_4A, AID_4B,
AID_4C, AID_4D, AID_4E, AID_4F};
std::vector<std::vector<uint8_t>> UNAUTHORIZED_AID = {AID_43, AID_46};
/* Authorized APDU for AID_40 */
std::vector<std::vector<uint8_t>> AUTHORIZED_APDU_AID_40 = {
{0x00, 0x06, 0x00, 0x00},
{0xA0, 0x06, 0x00, 0x00},
};
/* Unauthorized APDU for AID_40 */
std::vector<std::vector<uint8_t>> UNAUTHORIZED_APDU_AID_40 = {
{0x00, 0x08, 0x00, 0x00, 0x00},
{0x80, 0x06, 0x00, 0x00},
{0xA0, 0x08, 0x00, 0x00, 0x00},
{0x94, 0x06, 0x00, 0x00, 0x00},
};
/* Authorized APDU for AID_41 */
std::vector<std::vector<uint8_t>> AUTHORIZED_APDU_AID_41 = {
{0x94, 0x06, 0x00, 0x00},
{0x94, 0x08, 0x00, 0x00, 0x00},
{0x94, 0x0C, 0x00, 0x00, 0x01, 0xAA, 0x00},
{0x94, 0x0A, 0x00, 0x00, 0x01, 0xAA}};
/* Unauthorized APDU for AID_41 */
std::vector<std::vector<uint8_t>> UNAUTHORIZED_APDU_AID_41 = {
{0x00, 0x06, 0x00, 0x00},
{0x80, 0x06, 0x00, 0x00},
{0xA0, 0x06, 0x00, 0x00},
{0x00, 0x08, 0x00, 0x00, 0x00},
{0x00, 0x0A, 0x00, 0x00, 0x01, 0xAA},
{0x80, 0x0A, 0x00, 0x00, 0x01, 0xAA},
{0xA0, 0x0A, 0x00, 0x00, 0x01, 0xAA},
{0x80, 0x08, 0x00, 0x00, 0x00},
{0xA0, 0x08, 0x00, 0x00, 0x00},
{0x00, 0x0C, 0x00, 0x00, 0x01, 0xAA, 0x00},
{0x80, 0x0C, 0x00, 0x00, 0x01, 0xAA, 0x00},
{0xA0, 0x0C, 0x00, 0x00, 0x01, 0xAA, 0x00},
};
std::shared_ptr<aidl::android::se::omapi::ISecureElementService> mOmapiSeService;
std::map<std::string, std::shared_ptr<aidl::android::se::omapi::ISecureElementReader>>
mVSReaders = {};
};
TEST_P(OMAPISEAccessControlTest, TestAuthorizedAID) {
testSelectableAid(AUTHORIZED_AID);
}
TEST_P(OMAPISEAccessControlTest, TestUnauthorizedAID) {
testUnauthorisedAid(UNAUTHORIZED_AID);
}
TEST_P(OMAPISEAccessControlTest, TestAuthorizedAPDUAID40) {
testTransmitAPDU(AID_40, AUTHORIZED_APDU_AID_40);
}
TEST_P(OMAPISEAccessControlTest, TestUnauthorisedAPDUAID40) {
testUnauthorisedAPDU(AID_40, UNAUTHORIZED_APDU_AID_40);
}
TEST_P(OMAPISEAccessControlTest, TestAuthorizedAPDUAID41) {
testTransmitAPDU(AID_41, AUTHORIZED_APDU_AID_41);
}
TEST_P(OMAPISEAccessControlTest, TestUnauthorisedAPDUAID41) {
testUnauthorisedAPDU(AID_41, UNAUTHORIZED_APDU_AID_41);
}
INSTANTIATE_TEST_SUITE_P(PerInstance, OMAPISEAccessControlTest,
testing::ValuesIn(::android::getAidlHalInstanceNames(
aidl::android::se::omapi::ISecureElementService::descriptor)),
android::hardware::PrintInstanceNameToString);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(OMAPISEAccessControlTest);
} // namespace

View File

@@ -0,0 +1,54 @@
//
// Copyright (C) 2021 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.
//
package {
default_applicable_licenses: ["Android-Apache-2.0"],
}
cc_test {
name: "VtsHalOmapiSeServiceV1_TargetTest",
defaults: [
"VtsHalTargetTestDefaults",
"use_libaidlvintf_gtest_helper_static",
],
srcs: [
"VtsHalOmapiSeServiceV1_TargetTest.cpp",
],
shared_libs: [
"libbase",
"liblog",
"libcutils",
"libhidlbase",
"libnativehelper",
"libutils",
"libbinder_ndk",
],
static_libs: [
"VtsHalHidlTargetTestBase",
"android.se.omapi-V1-ndk",
],
cflags: [
"-O0",
"-g",
"-Wall",
"-Werror",
],
require_root: true,
test_suites: [
"general-tests",
"vts",
],
}

View File

@@ -0,0 +1,609 @@
/*
* Copyright (C) 2021 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/se/omapi/BnSecureElementListener.h>
#include <aidl/android/se/omapi/ISecureElementChannel.h>
#include <aidl/android/se/omapi/ISecureElementListener.h>
#include <aidl/android/se/omapi/ISecureElementReader.h>
#include <aidl/android/se/omapi/ISecureElementService.h>
#include <aidl/android/se/omapi/ISecureElementSession.h>
#include <VtsCoreUtil.h>
#include <aidl/Gtest.h>
#include <aidl/Vintf.h>
#include <android-base/logging.h>
#include <android/binder_manager.h>
#include <binder/IServiceManager.h>
#include <cutils/properties.h>
#include <gtest/gtest.h>
#include <hidl/GtestPrinter.h>
#include <hidl/ServiceManagement.h>
#include <utils/String16.h>
using namespace std;
using namespace ::testing;
using namespace android;
int main(int argc, char** argv) {
InitGoogleTest(&argc, argv);
int status = RUN_ALL_TESTS();
return status;
}
namespace {
class OMAPISEServiceHalTest : public TestWithParam<std::string> {
protected:
class SEListener : public ::aidl::android::se::omapi::BnSecureElementListener {};
void testSelectableAid(
std::shared_ptr<aidl::android::se::omapi::ISecureElementReader> reader,
std::vector<uint8_t> aid, std::vector<uint8_t>& selectResponse) {
std::shared_ptr<aidl::android::se::omapi::ISecureElementSession> session;
std::shared_ptr<aidl::android::se::omapi::ISecureElementChannel> channel;
auto seListener = ndk::SharedRefBase::make<::OMAPISEServiceHalTest::SEListener>();
ASSERT_NE(reader, nullptr) << "reader is null";
bool status = false;
auto res = reader->isSecureElementPresent(&status);
ASSERT_TRUE(res.isOk()) << res.getMessage();
ASSERT_TRUE(status);
res = reader->openSession(&session);
ASSERT_TRUE(res.isOk()) << res.getMessage();
ASSERT_NE(session, nullptr) << "Could not open session";
res = session->openLogicalChannel(aid, 0x00, seListener, &channel);
ASSERT_TRUE(res.isOk()) << res.getMessage();
ASSERT_NE(channel, nullptr) << "Could not open channel";
res = channel->getSelectResponse(&selectResponse);
ASSERT_TRUE(res.isOk()) << "failed to get Select Response";
ASSERT_GE(selectResponse.size(), 2);
if (channel != nullptr) channel->close();
if (session != nullptr) session->close();
ASSERT_EQ((selectResponse[selectResponse.size() - 1] & 0xFF), (0x00));
ASSERT_EQ((selectResponse[selectResponse.size() - 2] & 0xFF), (0x90));
}
void testNonSelectableAid(
std::shared_ptr<aidl::android::se::omapi::ISecureElementReader> reader,
std::vector<uint8_t> aid) {
std::shared_ptr<aidl::android::se::omapi::ISecureElementSession> session;
std::shared_ptr<aidl::android::se::omapi::ISecureElementChannel> channel;
auto seListener = ndk::SharedRefBase::make<::OMAPISEServiceHalTest::SEListener>();
ASSERT_NE(reader, nullptr) << "reader is null";
bool status = false;
auto res = reader->isSecureElementPresent(&status);
ASSERT_TRUE(res.isOk()) << res.getMessage();
ASSERT_TRUE(status);
res = reader->openSession(&session);
ASSERT_TRUE(res.isOk()) << res.getMessage();
ASSERT_NE(session, nullptr) << "Could not open session";
res = session->openLogicalChannel(aid, 0x00, seListener, &channel);
if (channel != nullptr) channel->close();
if (session != nullptr) session->close();
LOG(ERROR) << res.getMessage();
ASSERT_FALSE(res.isOk()) << "expected to fail to open channel for this test";
}
/**
* Verifies TLV data
*
* @return true if the data is tlv formatted, false otherwise
*/
bool verifyBerTlvData(std::vector<uint8_t> tlv) {
if (tlv.size() == 0) {
LOG(ERROR) << "Invalid tlv, null";
return false;
}
int i = 0;
if ((tlv[i++] & 0x1F) == 0x1F) {
// extra byte for TAG field
i++;
}
int len = tlv[i++] & 0xFF;
if (len > 127) {
// more than 1 byte for length
int bytesLength = len - 128;
len = 0;
for (int j = bytesLength; j > 0; j--) {
len += (len << 8) + (tlv[i++] & 0xFF);
}
}
// Additional 2 bytes for the SW
return (tlv.size() == (i + len + 2));
}
void internalTransmitApdu(
std::shared_ptr<aidl::android::se::omapi::ISecureElementReader> reader,
std::vector<uint8_t> apdu, std::vector<uint8_t>& transmitResponse) {
std::shared_ptr<aidl::android::se::omapi::ISecureElementSession> session;
std::shared_ptr<aidl::android::se::omapi::ISecureElementChannel> channel;
auto seListener = ndk::SharedRefBase::make<::OMAPISEServiceHalTest::SEListener>();
std::vector<uint8_t> selectResponse = {};
ASSERT_NE(reader, nullptr) << "reader is null";
bool status = false;
auto res = reader->isSecureElementPresent(&status);
ASSERT_TRUE(res.isOk()) << res.getMessage();
ASSERT_TRUE(status);
res = reader->openSession(&session);
ASSERT_TRUE(res.isOk()) << res.getMessage();
ASSERT_NE(session, nullptr) << "Could not open session";
res = session->openLogicalChannel(SELECTABLE_AID, 0x00, seListener, &channel);
ASSERT_TRUE(res.isOk()) << res.getMessage();
ASSERT_NE(channel, nullptr) << "Could not open channel";
res = channel->getSelectResponse(&selectResponse);
ASSERT_TRUE(res.isOk()) << "failed to get Select Response";
ASSERT_GE(selectResponse.size(), 2);
res = channel->transmit(apdu, &transmitResponse);
if (channel != nullptr) channel->close();
if (session != nullptr) session->close();
LOG(INFO) << "STATUS OF TRNSMIT: " << res.getExceptionCode()
<< " Message: " << res.getMessage();
ASSERT_TRUE(res.isOk()) << "failed to transmit";
}
bool supportOMAPIReaders() {
return (deviceSupportsFeature(FEATURE_SE_OMAPI_ESE.c_str()));
}
void SetUp() override {
LOG(INFO) << "get OMAPI service with name:" << GetParam();
::ndk::SpAIBinder ks2Binder(AServiceManager_getService(GetParam().c_str()));
mOmapiSeService = aidl::android::se::omapi::ISecureElementService::fromBinder(ks2Binder);
ASSERT_TRUE(mOmapiSeService);
std::vector<std::string> readers = {};
if (omapiSecureService() != NULL) {
auto status = omapiSecureService()->getReaders(&readers);
ASSERT_TRUE(status.isOk()) << status.getMessage();
for (auto readerName : readers) {
// Filter eSE readers only
if (readerName.find(ESE_READER_PREFIX, 0) != std::string::npos) {
std::shared_ptr<::aidl::android::se::omapi::ISecureElementReader> reader;
status = omapiSecureService()->getReader(readerName, &reader);
ASSERT_TRUE(status.isOk()) << status.getMessage();
mVSReaders[readerName] = reader;
}
}
}
}
void TearDown() override {
if (mOmapiSeService != nullptr) {
if (mVSReaders.size() > 0) {
for (const auto& [name, reader] : mVSReaders) {
reader->closeSessions();
}
}
}
}
bool isDebuggableBuild() {
char value[PROPERTY_VALUE_MAX] = {0};
property_get("ro.system.build.type", value, "");
if (strcmp(value, "userdebug") == 0) {
return true;
}
if (strcmp(value, "eng") == 0) {
return true;
}
return false;
}
std::shared_ptr<aidl::android::se::omapi::ISecureElementService> omapiSecureService() {
return mOmapiSeService;
}
static inline std::string const ESE_READER_PREFIX = "eSE";
static inline std::string const FEATURE_SE_OMAPI_ESE = "android.hardware.se.omapi.ese";
std::vector<uint8_t> SELECTABLE_AID = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x31};
std::vector<uint8_t> LONG_SELECT_RESPONSE_AID = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41,
0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64,
0x43, 0x54, 0x53, 0x32};
std::vector<uint8_t> NON_SELECTABLE_AID = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0xFF};
std::vector<std::vector<uint8_t>> ILLEGAL_COMMANDS_TRANSMIT = {
{0x00, 0x70, 0x00, 0x00},
{0x00, 0x70, 0x80, 0x00},
{0x00, 0xA4, 0x04, 0x04, 0x10, 0x4A, 0x53, 0x52, 0x31, 0x37, 0x37,
0x54, 0x65, 0x73, 0x74, 0x65, 0x72, 0x20, 0x31, 0x2E, 0x30}};
/* OMAPI APDU Test case 1 and 3 */
std::vector<std::vector<uint8_t>> NO_DATA_APDU = {{0x00, 0x06, 0x00, 0x00},
{0x80, 0x06, 0x00, 0x00},
{0xA0, 0x06, 0x00, 0x00},
{0x94, 0x06, 0x00, 0x00},
{0x00, 0x0A, 0x00, 0x00, 0x01, 0xAA},
{0x80, 0x0A, 0x00, 0x00, 0x01, 0xAA},
{0xA0, 0x0A, 0x00, 0x00, 0x01, 0xAA},
{0x94, 0x0A, 0x00, 0x00, 0x01, 0xAA}};
/* OMAPI APDU Test case 2 and 4 */
std::vector<std::vector<uint8_t>> DATA_APDU = {{0x00, 0x08, 0x00, 0x00, 0x00},
{0x80, 0x08, 0x00, 0x00, 0x00},
{0xA0, 0x08, 0x00, 0x00, 0x00},
{0x94, 0x08, 0x00, 0x00, 0x00},
{0x00, 0x0C, 0x00, 0x00, 0x01, 0xAA, 0x00},
{0x80, 0x0C, 0x00, 0x00, 0x01, 0xAA, 0x00},
{0xA0, 0x0C, 0x00, 0x00, 0x01, 0xAA, 0x00},
{0x94, 0x0C, 0x00, 0x00, 0x01, 0xAA, 0x00}};
/* Case 2 APDU command expects the P2 received in the SELECT command as 1-byte outgoing data */
std::vector<uint8_t> CHECK_SELECT_P2_APDU = {0x00, 0xF4, 0x00, 0x00, 0x00};
/* OMAPI APDU Test case 1 and 3 */
std::vector<std::vector<uint8_t>> SW_62xx_NO_DATA_APDU = {{0x00, 0xF3, 0x00, 0x06},
{0x00, 0xF3, 0x00, 0x0A, 0x01, 0xAA}};
/* OMAPI APDU Test case 2 and 4 */
std::vector<uint8_t> SW_62xx_DATA_APDU = {0x00, 0xF3, 0x00, 0x08, 0x00};
std::vector<uint8_t> SW_62xx_VALIDATE_DATA_APDU = {0x00, 0xF3, 0x00, 0x0C, 0x01, 0xAA, 0x00};
std::vector<std::vector<uint8_t>> SW_62xx = {
{0x62, 0x00}, {0x62, 0x81}, {0x62, 0x82}, {0x62, 0x83}, {0x62, 0x85}, {0x62, 0xF1},
{0x62, 0xF2}, {0x63, 0xF1}, {0x63, 0xF2}, {0x63, 0xC2}, {0x62, 0x02}, {0x62, 0x80},
{0x62, 0x84}, {0x62, 0x86}, {0x63, 0x00}, {0x63, 0x81}};
std::vector<std::vector<uint8_t>> SEGMENTED_RESP_APDU = {
// Get response Case2 61FF+61XX with answer length (P1P2) of 0x0800, 2048 bytes
{0x00, 0xC2, 0x08, 0x00, 0x00},
// Get response Case4 61FF+61XX with answer length (P1P2) of 0x0800, 2048 bytes
{0x00, 0xC4, 0x08, 0x00, 0x02, 0x12, 0x34, 0x00},
// Get response Case2 6100+61XX with answer length (P1P2) of 0x0800, 2048 bytes
{0x00, 0xC6, 0x08, 0x00, 0x00},
// Get response Case4 6100+61XX with answer length (P1P2) of 0x0800, 2048 bytes
{0x00, 0xC8, 0x08, 0x00, 0x02, 0x12, 0x34, 0x00},
// Test device buffer capacity 7FFF data
{0x00, 0xC2, 0x7F, 0xFF, 0x00},
// Get response 6CFF+61XX with answer length (P1P2) of 0x0800, 2048 bytes
{0x00, 0xCF, 0x08, 0x00, 0x00},
// Get response with another CLA with answer length (P1P2) of 0x0800, 2048 bytes
{0x94, 0xC2, 0x08, 0x00, 0x00}};
long SERVICE_CONNECTION_TIME_OUT = 3000;
std::shared_ptr<aidl::android::se::omapi::ISecureElementService> mOmapiSeService;
std::map<std::string, std::shared_ptr<aidl::android::se::omapi::ISecureElementReader>>
mVSReaders = {};
};
/** Tests getReaders API */
TEST_P(OMAPISEServiceHalTest, TestGetReaders) {
std::vector<std::shared_ptr<aidl::android::se::omapi::ISecureElementReader>> eseReaders =
{};
for (const auto& [name, reader] : mVSReaders) {
bool status = false;
LOG(INFO) << "Name of the reader: " << name;
if (reader) {
auto res = reader->isSecureElementPresent(&status);
ASSERT_TRUE(res.isOk()) << res.getMessage();
}
ASSERT_TRUE(status);
if (name.find(ESE_READER_PREFIX) == std::string::npos) {
LOG(ERROR) << "Incorrect Reader name";
FAIL();
}
if (name.find(ESE_READER_PREFIX, 0) != std::string::npos) {
eseReaders.push_back(reader);
} else {
LOG(INFO) << "Reader not supported: " << name;
FAIL();
}
}
if (deviceSupportsFeature(FEATURE_SE_OMAPI_ESE.c_str())) {
ASSERT_GE(eseReaders.size(), 1);
} else {
ASSERT_TRUE(eseReaders.size() == 0);
}
}
/** Tests OpenBasicChannel API when aid is null */
TEST_P(OMAPISEServiceHalTest, TestOpenBasicChannelNullAid) {
ASSERT_TRUE(supportOMAPIReaders() == true);
std::vector<uint8_t> aid = {};
auto seListener = ndk::SharedRefBase::make<::OMAPISEServiceHalTest::SEListener>();
if (mVSReaders.size() > 0) {
for (const auto& [name, reader] : mVSReaders) {
std::shared_ptr<aidl::android::se::omapi::ISecureElementSession> session;
std::shared_ptr<aidl::android::se::omapi::ISecureElementChannel> channel;
bool result = false;
auto status = reader->openSession(&session);
ASSERT_TRUE(status.isOk()) << status.getMessage();
if (!session) {
LOG(ERROR) << "Could not open session";
FAIL();
}
status = session->openBasicChannel(aid, 0x00, seListener, &channel);
ASSERT_TRUE(status.isOk()) << status.getMessage();
if (channel != nullptr) channel->close();
if (session != nullptr) session->close();
if (channel != nullptr) {
status = channel->isBasicChannel(&result);
ASSERT_TRUE(status.isOk()) << "Basic Channel cannot be opened";
}
}
}
}
/** Tests OpenBasicChannel API when aid is provided */
TEST_P(OMAPISEServiceHalTest, TestOpenBasicChannelNonNullAid) {
ASSERT_TRUE(supportOMAPIReaders() == true);
auto seListener = ndk::SharedRefBase::make<::OMAPISEServiceHalTest::SEListener>();
if (mVSReaders.size() > 0) {
for (const auto& [name, reader] : mVSReaders) {
std::shared_ptr<aidl::android::se::omapi::ISecureElementSession> session;
std::shared_ptr<aidl::android::se::omapi::ISecureElementChannel> channel;
bool result = false;
auto status = reader->openSession(&session);
ASSERT_TRUE(status.isOk()) << status.getMessage();
if (!session) {
LOG(ERROR) << "Could not open session";
FAIL();
}
status = session->openBasicChannel(SELECTABLE_AID, 0x00, seListener, &channel);
ASSERT_TRUE(status.isOk()) << status.getMessage();
if (channel != nullptr) channel->close();
if (session != nullptr) session->close();
if (channel != nullptr) {
status = channel->isBasicChannel(&result);
ASSERT_TRUE(status.isOk()) << "Basic Channel cannot be opened";
}
}
}
}
/** Tests Select API */
TEST_P(OMAPISEServiceHalTest, TestSelectableAid) {
ASSERT_TRUE(supportOMAPIReaders() == true);
if (mVSReaders.size() > 0) {
for (const auto& [name, reader] : mVSReaders) {
std::vector<uint8_t> selectResponse = {};
testSelectableAid(reader, SELECTABLE_AID, selectResponse);
}
}
}
/** Tests Select API */
TEST_P(OMAPISEServiceHalTest, TestLongSelectResponse) {
ASSERT_TRUE(supportOMAPIReaders() == true);
if (mVSReaders.size() > 0) {
for (const auto& [name, reader] : mVSReaders) {
std::vector<uint8_t> selectResponse = {};
testSelectableAid(reader, LONG_SELECT_RESPONSE_AID, selectResponse);
ASSERT_TRUE(verifyBerTlvData(selectResponse)) << "Select Response is not complete";
}
}
}
/** Test to fail open channel with wrong aid */
TEST_P(OMAPISEServiceHalTest, TestWrongAid) {
ASSERT_TRUE(supportOMAPIReaders() == true);
if (mVSReaders.size() > 0) {
for (const auto& [name, reader] : mVSReaders) {
testNonSelectableAid(reader, NON_SELECTABLE_AID);
}
}
}
/** Tests with invalid cmds in Transmit */
TEST_P(OMAPISEServiceHalTest, TestSecurityExceptionInTransmit) {
ASSERT_TRUE(supportOMAPIReaders() == true);
if (mVSReaders.size() > 0) {
for (const auto& [name, reader] : mVSReaders) {
std::shared_ptr<aidl::android::se::omapi::ISecureElementSession> session;
std::shared_ptr<aidl::android::se::omapi::ISecureElementChannel> channel;
auto seListener = ndk::SharedRefBase::make<::OMAPISEServiceHalTest::SEListener>();
std::vector<uint8_t> selectResponse = {};
ASSERT_NE(reader, nullptr) << "reader is null";
bool status = false;
auto res = reader->isSecureElementPresent(&status);
ASSERT_TRUE(res.isOk()) << res.getMessage();
ASSERT_TRUE(status);
res = reader->openSession(&session);
ASSERT_TRUE(res.isOk()) << res.getMessage();
ASSERT_NE(session, nullptr) << "Could not open session";
res = session->openLogicalChannel(SELECTABLE_AID, 0x00, seListener, &channel);
ASSERT_TRUE(res.isOk()) << res.getMessage();
ASSERT_NE(channel, nullptr) << "Could not open channel";
res = channel->getSelectResponse(&selectResponse);
ASSERT_TRUE(res.isOk()) << "failed to get Select Response";
ASSERT_GE(selectResponse.size(), 2);
ASSERT_EQ((selectResponse[selectResponse.size() - 1] & 0xFF), (0x00));
ASSERT_EQ((selectResponse[selectResponse.size() - 2] & 0xFF), (0x90));
for (auto cmd : ILLEGAL_COMMANDS_TRANSMIT) {
std::vector<uint8_t> response = {};
res = channel->transmit(cmd, &response);
ASSERT_EQ(res.getExceptionCode(), EX_SECURITY);
ASSERT_FALSE(res.isOk()) << "expected failed status for this test";
}
if (channel != nullptr) channel->close();
if (session != nullptr) session->close();
}
}
}
/**
* Tests Transmit API for all readers.
*
* Checks the return status and verifies the size of the
* response.
*/
TEST_P(OMAPISEServiceHalTest, TestTransmitApdu) {
ASSERT_TRUE(supportOMAPIReaders() == true);
if (mVSReaders.size() > 0) {
for (const auto& [name, reader] : mVSReaders) {
for (auto apdu : NO_DATA_APDU) {
std::vector<uint8_t> response = {};
internalTransmitApdu(reader, apdu, response);
ASSERT_GE(response.size(), 2);
ASSERT_EQ((response[response.size() - 1] & 0xFF), (0x00));
ASSERT_EQ((response[response.size() - 2] & 0xFF), (0x90));
}
for (auto apdu : DATA_APDU) {
std::vector<uint8_t> response = {};
internalTransmitApdu(reader, apdu, response);
/* 256 byte data and 2 bytes of status word */
ASSERT_GE(response.size(), 258);
ASSERT_EQ((response[response.size() - 1] & 0xFF), (0x00));
ASSERT_EQ((response[response.size() - 2] & 0xFF), (0x90));
}
}
}
}
/**
* Tests if underlying implementations returns the correct Status Word
*
* TO verify that :
* - the device does not modify the APDU sent to the Secure Element
* - the warning code is properly received by the application layer as SW answer
* - the verify that the application layer can fetch the additionnal data (when present)
*/
TEST_P(OMAPISEServiceHalTest, testStatusWordTransmit) {
ASSERT_TRUE(supportOMAPIReaders() == true);
if (mVSReaders.size() > 0) {
for (const auto& [name, reader] : mVSReaders) {
for (auto apdu : SW_62xx_NO_DATA_APDU) {
for (uint8_t i = 0x00; i < SW_62xx.size(); i++) {
apdu[2] = i + 1;
std::vector<uint8_t> response = {};
internalTransmitApdu(reader, apdu, response);
std::vector<uint8_t> SW = SW_62xx[i];
ASSERT_GE(response.size(), 2);
ASSERT_EQ(response[response.size() - 1], SW[1]);
ASSERT_EQ(response[response.size() - 2], SW[0]);
}
}
for (uint8_t i = 0x00; i < SW_62xx.size(); i++) {
std::vector<uint8_t> apdu = SW_62xx_DATA_APDU;
apdu[2] = i + 1;
std::vector<uint8_t> response = {};
internalTransmitApdu(reader, apdu, response);
std::vector<uint8_t> SW = SW_62xx[i];
ASSERT_GE(response.size(), 3);
ASSERT_EQ(response[response.size() - 1], SW[1]);
ASSERT_EQ(response[response.size() - 2], SW[0]);
}
for (uint8_t i = 0x00; i < SW_62xx.size(); i++) {
std::vector<uint8_t> apdu = SW_62xx_VALIDATE_DATA_APDU;
apdu[2] = i + 1;
std::vector<uint8_t> response = {};
internalTransmitApdu(reader, apdu, response);
ASSERT_GE(response.size(), apdu.size() + 2);
std::vector<uint8_t> responseSubstring((response.begin() + 0),
(response.begin() + apdu.size()));
// We should not care about which channel number is actually assigned.
responseSubstring[0] = apdu[0];
ASSERT_TRUE((responseSubstring == apdu));
std::vector<uint8_t> SW = SW_62xx[i];
ASSERT_EQ(response[response.size() - 1], SW[1]);
ASSERT_EQ(response[response.size() - 2], SW[0]);
}
}
}
}
/** Test if the responses are segmented by the underlying implementation */
TEST_P(OMAPISEServiceHalTest, TestSegmentedResponseTransmit) {
ASSERT_TRUE(supportOMAPIReaders() == true);
if (mVSReaders.size() > 0) {
for (const auto& [name, reader] : mVSReaders) {
for (auto apdu : SEGMENTED_RESP_APDU) {
std::vector<uint8_t> response = {};
internalTransmitApdu(reader, apdu, response);
int expectedLength = (0x00 << 24) | (0x00 << 16) | (apdu[2] << 8) | apdu[3];
ASSERT_EQ(response.size(), (expectedLength + 2));
ASSERT_EQ((response[response.size() - 1] & 0xFF), (0x00));
ASSERT_EQ((response[response.size() - 2] & 0xFF), (0x90));
ASSERT_EQ((response[response.size() - 3] & 0xFF), (0xFF));
}
}
}
}
/**
* Tests the P2 value of the select command.
*
* Verifies that the default P2 value (0x00) is not modified by the underlying implementation.
*/
TEST_P(OMAPISEServiceHalTest, TestP2Value) {
ASSERT_TRUE(supportOMAPIReaders() == true);
if (mVSReaders.size() > 0) {
for (const auto& [name, reader] : mVSReaders) {
std::vector<uint8_t> response = {};
internalTransmitApdu(reader, CHECK_SELECT_P2_APDU, response);
ASSERT_GE(response.size(), 3);
ASSERT_EQ((response[response.size() - 1] & 0xFF), (0x00));
ASSERT_EQ((response[response.size() - 2] & 0xFF), (0x90));
ASSERT_EQ((response[response.size() - 3] & 0xFF), (0x00));
}
}
}
INSTANTIATE_TEST_SUITE_P(PerInstance, OMAPISEServiceHalTest,
testing::ValuesIn(::android::getAidlHalInstanceNames(
aidl::android::se::omapi::ISecureElementService::descriptor)),
android::hardware::PrintInstanceNameToString);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(OMAPISEServiceHalTest);
} // namespace

17
omapi/java/Android.bp Normal file
View File

@@ -0,0 +1,17 @@
package {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
// all of the 'license_kinds' from "frameworks_base_license"
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_base_license"],
}
filegroup {
name: "framework-omapi-sources",
srcs: [
"**/*.java",
"**/*.aidl",
],
visibility: ["//frameworks/base"],
}

View File

@@ -170,7 +170,9 @@ public final class Reader {
try {
closeSessions();
return mReader.reset();
} catch (RemoteException ignore) {return false;}
} catch (RemoteException ignore) {
return false;
}
}
}
}

View File

@@ -230,20 +230,20 @@ public final class SEService {
* is not exist.
* @return A Reader object for this uicc slot.
*/
public @NonNull Reader getUiccReader(int slotNumber) {
if (slotNumber < 1) {
throw new IllegalArgumentException("slotNumber should be larger than 0");
}
loadReaders();
public @NonNull Reader getUiccReader(int slotNumber) {
if (slotNumber < 1) {
throw new IllegalArgumentException("slotNumber should be larger than 0");
}
loadReaders();
String readerName = UICC_TERMINAL + slotNumber;
Reader reader = mReaders.get(readerName);
String readerName = UICC_TERMINAL + slotNumber;
Reader reader = mReaders.get(readerName);
if (reader == null) {
if (reader == null) {
throw new IllegalArgumentException("Reader:" + readerName + " doesn't exist");
}
}
return reader;
return reader;
}
/**