summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-05-10 07:07:18 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-05-10 07:07:18 +0000
commitc6c1ea7c835fbd565b67ea9ae61683f57a1c509f (patch)
tree387d2f7774be844577676dfc96065f00a1d41a70
parentd97725cd738aaa9a00989ad769dd4da8b5fe515d (diff)
parent71e487c437e0d3d33023e4a6357528a771950abe (diff)
downloadSecureElement-aml_ext_331112010.tar.gz
Snap for 8564071 from 71e487c437e0d3d33023e4a6357528a771950abe to mainline-extservices-releaseaml_ext_331814220aml_ext_331412000aml_ext_331312000aml_ext_331112010aml_ext_331012020android13-mainline-extservices-release
Change-Id: I668066ba3b813831c817b3ec8abcc0bf3589649f
-rw-r--r--Android.bp20
-rwxr-xr-xAndroidManifest.xml16
-rwxr-xr-xNOTICE193
-rw-r--r--TEST_MAPPING8
-rw-r--r--etc/hal_uuid_map_config.xml41
-rw-r--r--res/values/config.xml4
-rw-r--r--secure_element-service.xml10
-rwxr-xr-x[-rw-r--r--]src/com/android/se/Channel.java40
-rw-r--r--src/com/android/se/SecureElementService.java211
-rw-r--r--src/com/android/se/Terminal.java119
-rwxr-xr-xsrc/com/android/se/internal/Util.java2
-rw-r--r--src/com/android/se/security/AccessControlEnforcer.java21
-rw-r--r--src/com/android/se/security/HalRefDoParser.java250
-rw-r--r--src/com/android/se/security/gpac/AID_REF_DO.java4
-rw-r--r--src/com/android/se/security/gpac/BerTlv.java2
-rw-r--r--src/com/android/se/security/gpac/Hash_REF_DO.java4
-rw-r--r--src/com/android/se/security/gpac/PERM_AR_DO.java2
-rw-r--r--src/com/android/se/security/gpac/PKG_REF_DO.java4
-rw-r--r--tests/unit/Android.bp32
-rw-r--r--tests/unit/AndroidManifest.xml29
-rw-r--r--tests/unit/AndroidTest.xml33
-rw-r--r--tests/unit/src/com/android/se/SecureElementVendorStableInterfaceFlagTest.java64
22 files changed, 806 insertions, 303 deletions
diff --git a/Android.bp b/Android.bp
index f7941f9..ee4f8e0 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,3 +1,23 @@
+package {
+ default_applicable_licenses: [
+ "packages_apps_SecureElement_license",
+ "Android-Apache-2.0",
+ ],
+}
+
+// See: http://go/android-license-faq
+license {
+ name: "packages_apps_SecureElement_license",
+ package_name: "Android Secure Element",
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ "SPDX-license-identifier-BSD",
+ ],
+ license_text: [
+ "NOTICE",
+ ],
+}
+
genrule {
name: "statslog-secure-element-java-gen",
tools: ["stats-log-api-gen"],
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index a26b112..33477eb 100755
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -1,14 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.se"
- android:sharedUserId="android.uid.se">
+ package="com.android.se"
+ android:sharedUserId="android.uid.se">
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
<application android:name=".SEApplication"
- android:label="SecureElementApplication"
- android:persistent="true"
- android:directBootAware="true">
+ android:label="SecureElementApplication"
+ android:persistent="true"
+ android:directBootAware="true"
+ android:memtagMode="async">
<service android:name=".SecureElementService"
- android:visibleToInstantApps="true">
+ android:visibleToInstantApps="true"
+ android:exported="true">
<intent-filter>
<action android:name="android.se.omapi.ISecureElementService"/>
</intent-filter>
diff --git a/NOTICE b/NOTICE
index 659696b..c1a3121 100755
--- a/NOTICE
+++ b/NOTICE
@@ -40,196 +40,3 @@
See the License for the specific language governing permissions and
limitations under the License.
- ----------------------------------------------------------------------------
-
- Copyright (C) 2011, 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.
-
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
diff --git a/TEST_MAPPING b/TEST_MAPPING
new file mode 100644
index 0000000..323ab4d
--- /dev/null
+++ b/TEST_MAPPING
@@ -0,0 +1,8 @@
+{
+ "postsubmit": [
+ {
+ "name": "SecureElementInstrumentationTests",
+ "keywords": ["primary-device"]
+ }
+ ]
+}
diff --git a/etc/hal_uuid_map_config.xml b/etc/hal_uuid_map_config.xml
new file mode 100644
index 0000000..5388697
--- /dev/null
+++ b/etc/hal_uuid_map_config.xml
@@ -0,0 +1,41 @@
+<!-- Vendor mapping file -->
+<!-- Sample UUID to list of UIDs mapping file -->
+
+<!-- UUID: Universally Unique IDentifier -->
+<!-- 16 Byte UUID need to be generated by vendors to add new entry -->
+<!-- As per global platform access control spec, UUID is expected to be of -->
+<!-- length 20 bytes. While using this UUID, it is expected to be -->
+<!-- automatically padded with ffffffff in initial 4 bytes of 20 Byte length -->
+
+<!-- UID: user identifier of the service -->
+
+<!-- This mapping file should contain an entry for VTS tests, since VTS -->
+<!-- tests run as root, user identifier 0 should be mapped to its -->
+<!-- corresponding UUID to allow VTS tests to access secure element -->
+<!-- For VTS tests use UID: 0 and UUID: 9f36407ead0639fc966f14dde7970f68 -->
+
+<ref_do>
+ <!-- mapping entries to map unique identifiers to device hal services -->
+ <!-- uids -->
+
+ <!-- UUID would be automatically padding with ffffffff to fulfill 20 -->
+ <!-- bytes in access rule. For example for -->
+ <!-- UUID:9f36407ead0639fc966f14dde7970f68 after padding it should look -->
+ <!-- like ffffffff9f36407ead0639fc966f14dde7970f68 -->
+ <uuid_ref_do>
+ <uids>
+ <uid>0</uid>
+ </uids>
+ <uuid>9f36407ead0639fc966f14dde7970f68</uuid>
+ </uuid_ref_do>
+
+ <!-- Sample mapping entry with UIDs:1096 and 1097 mapped to -->
+ <!-- UUID:9f36407ead0639fc966f14dde7970f68 -->
+ <uuid_ref_do>
+ <uids>
+ <uid>1096</uid>
+ <uid>1097</uid>
+ </uids>
+ <uuid>a9b7ba70783b317e9998dc4dd82eb3c5</uuid>
+ </uuid_ref_do>
+</ref_do>
diff --git a/res/values/config.xml b/res/values/config.xml
index cc310a0..5811b10 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -3,4 +3,8 @@
<!-- The list of AIDs are the candidate of the ARA AID in ESE.
The first available AID will be taken as the ARA AID. -->
<string-array name="config_ara_aid_candidate_list_ese" translatable="false" />
+
+ <!-- To enable vendor stable service, set this to true and
+ make sure its vntf manifest entry is also configured. -->
+ <bool name="secure_element_vintf_enabled">false</bool>
</resources>
diff --git a/secure_element-service.xml b/secure_element-service.xml
new file mode 100644
index 0000000..37c7465
--- /dev/null
+++ b/secure_element-service.xml
@@ -0,0 +1,10 @@
+<manifest version="1.0" type="framework">
+ <hal format="aidl">
+ <name>android.se.omapi</name>
+ <version>1</version>
+ <interface>
+ <name>ISecureElementService</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/src/com/android/se/Channel.java b/src/com/android/se/Channel.java
index 4fbb2a0..73622fc 100644..100755
--- a/src/com/android/se/Channel.java
+++ b/src/com/android/se/Channel.java
@@ -89,21 +89,23 @@ public class Channel implements IBinder.DeathRecipient {
/**
* Closes the channel.
*/
- public synchronized void close() {
+ public void close() {
synchronized (mLock) {
- if (isBasicChannel()) {
- Log.i(mTag, "Close basic channel - Select without AID ...");
- mTerminal.selectDefaultApplication();
- }
-
- mTerminal.closeChannel(this);
+ if (isClosed())
+ return;
mIsClosed = true;
- if (mBinder != null) {
- mBinder.unlinkToDeath(this, 0);
- }
- if (mSession != null) {
- mSession.removeChannel(this);
- }
+ }
+ if (isBasicChannel()) {
+ Log.i(mTag, "Close basic channel - Select without AID ...");
+ mTerminal.selectDefaultApplication();
+ }
+
+ mTerminal.closeChannel(this);
+ if (mBinder != null) {
+ mBinder.unlinkToDeath(this, 0);
+ }
+ if (mSession != null) {
+ mSession.removeChannel(this);
}
}
@@ -211,7 +213,7 @@ public class Channel implements IBinder.DeathRecipient {
cla = (byte) ((cla & 0xBC) | channelNumber);
} else if (channelNumber < 20) {
// b7 = 1 indicates the further interindustry class byte coding
- boolean isSm = (cla & 0x0C) != 0;
+ boolean isSm = (((cla & 0x40) == 0x00) && ((cla & 0x0C) != 0));
cla = (byte) ((cla & 0xB0) | 0x40 | (channelNumber - 4));
if (isSm) {
cla |= 0x20;
@@ -328,5 +330,15 @@ public class Channel implements IBinder.DeathRecipient {
throw new ServiceSpecificException(SEService.IO_ERROR, e.getMessage());
}
}
+
+ @Override
+ public String getInterfaceHash() {
+ return ISecureElementChannel.HASH;
+ }
+
+ @Override
+ public int getInterfaceVersion() {
+ return ISecureElementChannel.VERSION;
+ }
}
}
diff --git a/src/com/android/se/SecureElementService.java b/src/com/android/se/SecureElementService.java
index 758fc77..92b3b51 100644
--- a/src/com/android/se/SecureElementService.java
+++ b/src/com/android/se/SecureElementService.java
@@ -34,6 +34,7 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
+import android.os.UserHandle;
import android.se.omapi.ISecureElementChannel;
import android.se.omapi.ISecureElementListener;
import android.se.omapi.ISecureElementReader;
@@ -45,6 +46,7 @@ import android.util.Log;
import com.android.se.Terminal.SecureElementReader;
import com.android.se.internal.ByteArrayConverter;
+import com.android.se.security.HalRefDoParser;
import java.io.FileDescriptor;
import java.io.IOException;
@@ -54,6 +56,7 @@ import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.NoSuchElementException;
+import java.util.Vector;
/**
* Underlying implementation for OMAPI SEService
@@ -62,51 +65,110 @@ public final class SecureElementService extends Service {
public static final String UICC_TERMINAL = "SIM";
public static final String ESE_TERMINAL = "eSE";
+ public static final String VSTABLE_SECURE_ELEMENT_SERVICE =
+ "android.se.omapi.ISecureElementService/default";
private final String mTag = "SecureElementService";
private static final boolean DEBUG = Build.IS_DEBUGGABLE;
// LinkedHashMap will maintain the order of insertion
private LinkedHashMap<String, Terminal> mTerminals = new LinkedHashMap<String, Terminal>();
private int mActiveSimCount = 0;
- private final ISecureElementService.Stub mSecureElementServiceBinder =
- new ISecureElementService.Stub() {
+ private class SecureElementServiceBinder extends ISecureElementService.Stub {
- @Override
- public String[] getReaders() throws RemoteException {
- return mTerminals.keySet().toArray(new String[mTerminals.size()]);
+ @Override
+ public String[] getReaders() throws RemoteException {
+ try {
+ // This determines calling process is application/framework
+ String packageName = getPackageNameFromCallingUid(Binder.getCallingUid());
+ Log.d(mTag, "getReaders() for " + packageName);
+ return mTerminals.keySet().toArray(new String[mTerminals.size()]);
+ } catch (AccessControlException e) {
+ // since packagename not found, UUID might be used to access
+ // allow only to use eSE readers with UUID based requests
+ Vector<String> eSEReaders = new Vector<String>();
+ for (String reader : mTerminals.keySet()) {
+ if (reader.startsWith(SecureElementService.ESE_TERMINAL)) {
+ Log.i(mTag, "Adding Reader: " + reader);
+ eSEReaders.add(reader);
+ }
}
- @Override
- public ISecureElementReader getReader(String reader)
- throws RemoteException {
- Log.d(mTag, "getReader() " + reader);
- Terminal terminal = getTerminal(reader);
- return terminal.new SecureElementReader(SecureElementService.this);
- }
+ return eSEReaders.toArray(new String[eSEReaders.size()]);
+ }
+ }
- @Override
- public synchronized boolean[] isNFCEventAllowed(String reader, byte[] aid,
- String[] packageNames)
- throws RemoteException {
- if (aid == null || aid.length == 0) {
- aid = new byte[]{0x00, 0x00, 0x00, 0x00, 0x00};
- }
- if (aid.length < 5 || aid.length > 16) {
- throw new IllegalArgumentException("AID out of range");
- }
- if (packageNames == null || packageNames.length == 0) {
- throw new IllegalArgumentException("package names not specified");
- }
- Terminal terminal = getTerminal(reader);
- return terminal.isNfcEventAllowed(getPackageManager(), aid, packageNames);
+ @Override
+ public ISecureElementReader getReader(String reader) throws RemoteException {
+ Log.d(mTag, "getReader() " + reader);
+ Terminal terminal = null;
+ try {
+ // This determines calling process is application/framework
+ String packageName = getPackageNameFromCallingUid(Binder.getCallingUid());
+ Log.d(mTag, "getReader() for " + packageName);
+ terminal = getTerminal(reader);
+ } catch (AccessControlException e) {
+ // since packagename not found, UUID might be used to access
+ // allow only to use eSE readers with UUID based requests
+ if (reader.startsWith(SecureElementService.ESE_TERMINAL)) {
+ terminal = getTerminal(reader);
+ } else {
+ Log.d(mTag, "only eSE readers can access SE using UUID");
}
+ }
+ if (terminal != null) {
+ return terminal.new SecureElementReader(SecureElementService.this);
+ } else {
+ throw new IllegalArgumentException("Reader: " + reader + " not supported");
+ }
+ }
- @Override
- protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
- for (Terminal terminal : mTerminals.values()) {
- terminal.dump(writer);
- }
- }
- };
+ @Override
+ public synchronized boolean[] isNfcEventAllowed(String reader, byte[] aid,
+ String[] packageNames, int userId) throws RemoteException {
+ if (aid == null || aid.length == 0) {
+ aid = new byte[]{0x00, 0x00, 0x00, 0x00, 0x00};
+ }
+ if (aid.length < 5 || aid.length > 16) {
+ throw new IllegalArgumentException("AID out of range");
+ }
+ if (packageNames == null || packageNames.length == 0) {
+ throw new IllegalArgumentException("package names not specified");
+ }
+ Terminal terminal = getTerminal(reader);
+ Context context;
+ try {
+ context = createContextAsUser(UserHandle.of(userId), /*flags=*/0);
+ } catch (IllegalStateException e) {
+ context = null;
+ Log.d(mTag, "fail to call createContextAsUser for userId:" + userId);
+ }
+ return context == null ? null : terminal.isNfcEventAllowed(
+ context.getPackageManager(), aid, packageNames);
+
+ }
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+ for (Terminal terminal : mTerminals.values()) {
+ terminal.dump(writer);
+ }
+ }
+
+ @Override
+ public String getInterfaceHash() {
+ return ISecureElementService.HASH;
+ }
+
+ @Override
+ public int getInterfaceVersion() {
+ return ISecureElementService.VERSION;
+ }
+ }
+
+ private final ISecureElementService.Stub mSecureElementServiceBinder =
+ new SecureElementServiceBinder();
+
+ private final ISecureElementService.Stub mSecureElementServiceBinderVntf =
+ new SecureElementServiceBinder();
public SecureElementService() {
super();
@@ -148,6 +210,17 @@ public final class SecureElementService extends Service {
Log.i(mTag, Thread.currentThread().getName() + " onCreate");
initialize();
createTerminals();
+
+ // Add vendor stable service only if it is configured
+ if (getResources().getBoolean(R.bool.secure_element_vintf_enabled)) {
+ ServiceManager.addService(VSTABLE_SECURE_ELEMENT_SERVICE,
+ mSecureElementServiceBinderVntf);
+ }
+
+ // Since ISecureElementService is marked with VINTF stability
+ // to use this same interface within the system partition, will use
+ // forceDowngradeToSystemStability and register it.
+ mSecureElementServiceBinder.forceDowngradeToSystemStability();
ServiceManager.addService(Context.SECURE_ELEMENT_SERVICE, mSecureElementServiceBinder);
}
@@ -232,6 +305,16 @@ public final class SecureElementService extends Service {
throw new AccessControlException("PackageName can not be determined");
}
+ private byte[] getUUIDFromCallingUid(int uid) {
+ byte[] uuid = HalRefDoParser.getInstance().findUUID(Binder.getCallingUid());
+
+ if (uuid != null) {
+ return uuid;
+ }
+
+ return null;
+ }
+
final class SecureElementSession extends ISecureElementSession.Stub {
private final SecureElementReader mReader;
@@ -314,12 +397,29 @@ public final class SecureElementService extends Service {
+ String.format("%02x ", p2 & 0xFF));
}
- String packageName = getPackageNameFromCallingUid(Binder.getCallingUid());
+ String packageName = null;
+ byte[] uuid = null;
+ try {
+ packageName = getPackageNameFromCallingUid(Binder.getCallingUid());
+ } catch (AccessControlException e) {
+ // Since packageName not found for calling process, try to find UUID mapping
+ // provided by vendors for the calling process UID
+ // (vendor provide UUID mapping for native services to access secure element)
+ Log.d(mTag, "openBasicChannel() trying to find mapping uuid");
+ // Allow UUID based access only on embedded secure elements eSE.
+ if (mReader.getTerminal().getName().startsWith(SecureElementService.ESE_TERMINAL)) {
+ uuid = getUUIDFromCallingUid(Binder.getCallingUid());
+ }
+ if (uuid == null) {
+ Log.e(mTag, "openBasicChannel() uuid mapping for calling uid is not found");
+ throw e;
+ }
+ }
Channel channel = null;
try {
channel = mReader.getTerminal().openBasicChannel(this, aid, p2, listener,
- packageName, Binder.getCallingPid());
+ packageName, uuid, Binder.getCallingPid());
} catch (IOException e) {
throw new ServiceSpecificException(SEService.IO_ERROR, e.getMessage());
} catch (NoSuchElementException e) {
@@ -333,7 +433,9 @@ public final class SecureElementService extends Service {
Log.i(mTag, "Open basic channel success. Channel: "
+ channel.getChannelNumber());
- mChannels.add(channel);
+ synchronized (mLock) {
+ mChannels.add(channel);
+ }
return channel.new SecureElementChannel();
}
@@ -354,12 +456,29 @@ public final class SecureElementService extends Service {
+ String.format("%02x ", p2 & 0xFF));
}
- String packageName = getPackageNameFromCallingUid(Binder.getCallingUid());
+ String packageName = null;
+ byte[] uuid = null;
+ try {
+ packageName = getPackageNameFromCallingUid(Binder.getCallingUid());
+ } catch (AccessControlException e) {
+ // Since packageName not found for calling process, try to find UUID mapping
+ // provided by vendors for the calling process UID
+ // (vendor provide UUID mapping for native services to access secure element)
+ Log.d(mTag, "openLogicalChannel() trying to find mapping uuid");
+ // Allow UUID based access only on embedded secure elements eSE.
+ if (mReader.getTerminal().getName().startsWith(SecureElementService.ESE_TERMINAL)) {
+ uuid = getUUIDFromCallingUid(Binder.getCallingUid());
+ }
+ if (uuid == null) {
+ Log.e(mTag, "openLogicalChannel() uuid mapping for calling uid is not found");
+ throw e;
+ }
+ }
Channel channel = null;
try {
channel = mReader.getTerminal().openLogicalChannel(this, aid, p2, listener,
- packageName, Binder.getCallingPid());
+ packageName, uuid, Binder.getCallingPid());
} catch (IOException e) {
throw new ServiceSpecificException(SEService.IO_ERROR, e.getMessage());
} catch (NoSuchElementException e) {
@@ -373,9 +492,21 @@ public final class SecureElementService extends Service {
Log.i(mTag, "openLogicalChannel() Success. Channel: "
+ channel.getChannelNumber());
- mChannels.add(channel);
+ synchronized (mLock) {
+ mChannels.add(channel);
+ }
return channel.new SecureElementChannel();
}
+
+ @Override
+ public String getInterfaceHash() {
+ return ISecureElementSession.HASH;
+ }
+
+ @Override
+ public int getInterfaceVersion() {
+ return ISecureElementSession.VERSION;
+ }
}
private final BroadcastReceiver mMultiSimConfigChangedReceiver = new BroadcastReceiver() {
diff --git a/src/com/android/se/Terminal.java b/src/com/android/se/Terminal.java
index 54dc256..d338cf8 100644
--- a/src/com/android/se/Terminal.java
+++ b/src/com/android/se/Terminal.java
@@ -24,6 +24,7 @@
package com.android.se;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -31,12 +32,14 @@ import android.hardware.secure_element.V1_0.ISecureElement;
import android.hardware.secure_element.V1_0.ISecureElementHalCallback;
import android.hardware.secure_element.V1_0.LogicalChannelResponse;
import android.hardware.secure_element.V1_0.SecureElementStatus;
+import android.os.Binder;
import android.os.Build;
import android.os.Handler;
import android.os.HwBinder;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
+import android.os.UserHandle;
import android.se.omapi.ISecureElementListener;
import android.se.omapi.ISecureElementReader;
import android.se.omapi.ISecureElementSession;
@@ -158,9 +161,19 @@ public class Terminal {
reason,
mName);
}
+
+ sendStateChangedBroadcast(state);
}
}
+ private void sendStateChangedBroadcast(boolean state) {
+ Intent intent = new Intent(SEService.ACTION_SECURE_ELEMENT_STATE_CHANGED);
+ intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ intent.putExtra(SEService.EXTRA_READER_NAME, mName);
+ intent.putExtra(SEService.EXTRA_READER_STATE, state);
+ mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
+ };
+
class SecureElementDeathRecipient implements HwBinder.DeathRecipient {
@Override
public void serviceDied(long cookie) {
@@ -319,11 +332,13 @@ public class Terminal {
/**
* Cleans up all the channels in use.
*/
- public synchronized void closeChannels() {
- Collection<Channel> col = mChannels.values();
- Channel[] channelList = col.toArray(new Channel[col.size()]);
- for (Channel channel : channelList) {
- channel.close();
+ public void closeChannels() {
+ synchronized (mLock) {
+ Collection<Channel> col = mChannels.values();
+ Channel[] channelList = col.toArray(new Channel[col.size()]);
+ for (Channel channel : channelList) {
+ channel.close();
+ }
}
}
@@ -418,9 +433,11 @@ public class Terminal {
/**
* Opens a Basic Channel with the given AID and P2 paramters
+ * with the given device app reference package name or uuid
*/
public Channel openBasicChannel(SecureElementSession session, byte[] aid, byte p2,
- ISecureElementListener listener, String packageName, int pid) throws IOException,
+ ISecureElementListener listener, String packageName, byte[] uuid,
+ int pid) throws IOException,
NoSuchElementException {
if (aid != null && aid.length == 0) {
aid = null;
@@ -432,19 +449,31 @@ public class Terminal {
ChannelAccess channelAccess = null;
if (packageName != null) {
- Log.w(mTag, "Enable access control on basic channel for " + packageName);
+ Log.w(mTag, "Enable access control on basic channel for package name: "
+ + packageName);
SecureElementStatsLog.write(
SecureElementStatsLog.SE_OMAPI_REPORTED,
SecureElementStatsLog.SE_OMAPI_REPORTED__OPERATION__OPEN_CHANNEL,
mName,
packageName);
- try {
- // For application without privilege permission or carrier privilege,
- // openBasicChannel with UICC terminals should be rejected.
- channelAccess = setUpChannelAccess(aid, packageName, pid, true);
- } catch (MissingResourceException e) {
- return null;
+ } else if (uuid != null) {
+ Log.w(mTag, "Enable access control on basic channel for uid: "
+ + Binder.getCallingUid()
+ + " UUID: " + Arrays.toString(uuid));
+ SecureElementStatsLog.write(
+ SecureElementStatsLog.SE_OMAPI_REPORTED,
+ SecureElementStatsLog.SE_OMAPI_REPORTED__OPERATION__OPEN_CHANNEL,
+ mName,
+ Arrays.toString(uuid));
+ }
+ try {
+ // For application without privilege permission or carrier privilege,
+ // openBasicChannel with UICC terminals should be rejected.
+ if (packageName != null || uuid != null) {
+ channelAccess = setUpChannelAccess(aid, packageName, uuid, pid, true);
}
+ } catch (MissingResourceException e) {
+ return null;
}
synchronized (mLock) {
@@ -502,14 +531,15 @@ public class Terminal {
*/
public Channel openLogicalChannelWithoutChannelAccess(byte[] aid) throws IOException,
NoSuchElementException {
- return openLogicalChannel(null, aid, (byte) 0x00, null, null, 0);
+ return openLogicalChannel(null, aid, (byte) 0x00, null, null, null, 0);
}
/**
- * Opens a logical Channel with AID.
+ * Opens a logical Channel with AID for the given package name or uuid
*/
public Channel openLogicalChannel(SecureElementSession session, byte[] aid, byte p2,
- ISecureElementListener listener, String packageName, int pid) throws IOException,
+ ISecureElementListener listener, String packageName,
+ byte[] uuid, int pid) throws IOException,
NoSuchElementException {
if (aid != null && aid.length == 0) {
aid = null;
@@ -527,11 +557,22 @@ public class Terminal {
SecureElementStatsLog.SE_OMAPI_REPORTED__OPERATION__OPEN_CHANNEL,
mName,
packageName);
- try {
- channelAccess = setUpChannelAccess(aid, packageName, pid, false);
- } catch (MissingResourceException | UnsupportedOperationException e) {
- return null;
+ } else if (uuid != null) {
+ Log.w(mTag, "Enable access control on logical channel for uid: "
+ + Binder.getCallingUid()
+ + " UUID: " + Arrays.toString(uuid));
+ SecureElementStatsLog.write(
+ SecureElementStatsLog.SE_OMAPI_REPORTED,
+ SecureElementStatsLog.SE_OMAPI_REPORTED__OPERATION__OPEN_CHANNEL,
+ mName,
+ Arrays.toString(uuid));
+ }
+ try {
+ if (packageName != null || uuid != null) {
+ channelAccess = setUpChannelAccess(aid, packageName, uuid, pid, false);
}
+ } catch (MissingResourceException | UnsupportedOperationException e) {
+ return null;
}
synchronized (mLock) {
@@ -670,17 +711,14 @@ public class Terminal {
*/
public boolean[] isNfcEventAllowed(PackageManager packageManager, byte[] aid,
String[] packageNames) {
- // Attempt to initialize the access control enforcer if it failed in the previous attempt
- // due to a kind of temporary failure or no rule was found.
+ if (!mIsConnected) {
+ // Return if not connected
+ return null;
+ }
+ // Return if the access control enforcer failed in previous attempt or no rule was found.
if (mAccessControlEnforcer == null || mAccessControlEnforcer.isNoRuleFound()) {
- try {
- initializeAccessControl();
- // Just finished to initialize the access control enforcer.
- // It is too much to check the refresh tag in this case.
- } catch (Exception e) {
- Log.i(mTag, "isNfcEventAllowed Exception: " + e.getMessage());
- return null;
- }
+ Log.i(mTag, "isNfcEventAllowed: No access rules for checking.");
+ return null;
}
mAccessControlEnforcer.setPackageManager(packageManager);
@@ -734,10 +772,10 @@ public class Terminal {
/**
* Initialize the Access Control and set up the channel access.
*/
- private ChannelAccess setUpChannelAccess(byte[] aid, String packageName, int pid,
+ private ChannelAccess setUpChannelAccess(byte[] aid, String packageName, byte[] uuid, int pid,
boolean isBasicChannel) throws IOException, MissingResourceException {
boolean checkRefreshTag = true;
- if (isPrivilegedApplication(packageName)) {
+ if (packageName != null && isPrivilegedApplication(packageName)) {
return ChannelAccess.getPrivilegeAccess(packageName, pid);
}
// Attempt to initialize the access control enforcer if it failed
@@ -753,7 +791,7 @@ public class Terminal {
mAccessControlEnforcer.setPackageManager(mContext.getPackageManager());
// Check carrier privilege when AID is not ISD-R
- if (getName().startsWith(SecureElementService.UICC_TERMINAL)
+ if (packageName != null && getName().startsWith(SecureElementService.UICC_TERMINAL)
&& !Arrays.equals(aid, ISD_R_AID)) {
try {
PackageManager pm = mContext.getPackageManager();
@@ -783,7 +821,7 @@ public class Terminal {
synchronized (mLock) {
try {
ChannelAccess channelAccess =
- mAccessControlEnforcer.setUpChannelAccess(aid, packageName,
+ mAccessControlEnforcer.setUpChannelAccess(aid, packageName, uuid,
checkRefreshTag);
channelAccess.setCallingPid(pid);
return channelAccess;
@@ -926,8 +964,9 @@ public class Terminal {
if (session == null) {
throw new NullPointerException("session is null");
}
- mSessions.remove(session);
+
synchronized (mLock) {
+ mSessions.remove(session);
if (mSessions.size() == 0) {
mDefaultApplicationSelectedOnBasicChannel = true;
}
@@ -956,5 +995,15 @@ public class Terminal {
public boolean reset() {
return Terminal.this.reset();
}
+
+ @Override
+ public String getInterfaceHash() {
+ return ISecureElementReader.HASH;
+ }
+
+ @Override
+ public int getInterfaceVersion() {
+ return ISecureElementReader.VERSION;
+ }
}
}
diff --git a/src/com/android/se/internal/Util.java b/src/com/android/se/internal/Util.java
index 8e9cfe3..8a52962 100755
--- a/src/com/android/se/internal/Util.java
+++ b/src/com/android/se/internal/Util.java
@@ -135,7 +135,7 @@ public class Util {
cla = (byte) ((cla & 0xBC) | channelNumber);
} else if (channelNumber < 20) {
// b7 = 1 indicates the further interindustry class byte coding
- boolean isSM = (cla & 0x0C) != 0;
+ boolean isSM = (((cla & 0x40) == 0x00) && ((cla & 0x0C) != 0));
cla = (byte) ((cla & 0xB0) | 0x40 | (channelNumber - 4));
if (isSM) {
cla |= 0x20;
diff --git a/src/com/android/se/security/AccessControlEnforcer.java b/src/com/android/se/security/AccessControlEnforcer.java
index 6d595d8..e6f08cf 100644
--- a/src/com/android/se/security/AccessControlEnforcer.java
+++ b/src/com/android/se/security/AccessControlEnforcer.java
@@ -271,8 +271,8 @@ public class AccessControlEnforcer {
}
/** Sets up the Channel Access for the given Package */
- public ChannelAccess setUpChannelAccess(byte[] aid, String packageName, boolean checkRefreshTag)
- throws IOException, MissingResourceException {
+ public ChannelAccess setUpChannelAccess(byte[] aid, String packageName, byte[] uuid,
+ boolean checkRefreshTag) throws IOException, MissingResourceException {
ChannelAccess channelAccess = null;
// check result of channel access during initialization procedure
if (mInitialChannelAccess.getAccess() == ChannelAccess.ACCESS.DENIED) {
@@ -281,7 +281,7 @@ public class AccessControlEnforcer {
}
// this is the new GP Access Control Enforcer implementation
if (mUseAra || mUseArf) {
- channelAccess = internal_setUpChannelAccess(aid, packageName,
+ channelAccess = internal_setUpChannelAccess(aid, packageName, uuid,
checkRefreshTag);
}
if (channelAccess == null || (channelAccess.getApduAccess() != ChannelAccess.ACCESS.ALLOWED
@@ -299,14 +299,23 @@ public class AccessControlEnforcer {
}
private synchronized ChannelAccess internal_setUpChannelAccess(byte[] aid,
- String packageName, boolean checkRefreshTag) throws IOException,
+ String packageName, byte[] uuid, boolean checkRefreshTag) throws IOException,
MissingResourceException {
- if (packageName == null || packageName.isEmpty()) {
+ if (uuid == null && (packageName == null || packageName.isEmpty())) {
throw new AccessControlException("package names must be specified");
}
try {
// estimate SHA-1 and SHA-256 hash values of the device application's certificate.
- List<byte[]> appCertHashes = getAppCertHashes(packageName);
+ List<byte[]> appCertHashes = null;
+ if (packageName != null) {
+ appCertHashes = getAppCertHashes(packageName);
+ } else {
+ if (uuid != null) {
+ appCertHashes = new ArrayList<byte[]>();
+ appCertHashes.add(uuid);
+ }
+ }
+
// APP certificates must be available => otherwise Exception
if (appCertHashes == null || appCertHashes.size() == 0) {
throw new AccessControlException(
diff --git a/src/com/android/se/security/HalRefDoParser.java b/src/com/android/se/security/HalRefDoParser.java
new file mode 100644
index 0000000..40ea7de
--- /dev/null
+++ b/src/com/android/se/security/HalRefDoParser.java
@@ -0,0 +1,250 @@
+/*
+ * 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 com.android.se.security;
+
+import android.os.Build;
+import android.os.SystemProperties;
+import android.util.Log;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParserFactory;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Parser for HAL_UID_MAP.XML
+ * Parses the xml file and collects HAL references (UUID) to identify the corresponding
+ * access rules for the HAL services.
+ */
+public class HalRefDoParser {
+
+ private static final boolean DEBUG = Build.IS_DEBUGGABLE;
+ private final String mTag = "SecureElement-HalRefDoParser";
+
+ private static final String PROP_PRODUCT_HARDWARE_SKU = "ro.boot.product.hardware.sku";
+ private static final String UUID_MAPPING_CONFIG_PREFIX = "hal_uuid_map_";
+ private static final String UUID_MAPPING_CONFIG_EXT = ".xml";
+ private static final String[] UUID_MAPPING_CONFIG_PATHS = {"/odm/etc/", "/vendor/etc/",
+ "/etc/"};
+
+ // Holds UUID to UIDs mapping
+ private final Map<Integer, byte[]> mUUIDMap = new HashMap<Integer, byte[]>();
+
+ private static final String REF_DO = "ref_do";
+ private static final String UUID_REF_DO = "uuid_ref_do";
+ private static final String UUID = "uuid";
+ private static final String UIDS = "uids";
+ private static final String UID = "uid";
+
+ private static final byte[] PADDING_BYTES = {
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff};
+
+ private HalRefDoParser() {
+ parseUuidMappings();
+ }
+
+ private static class HalRefParserSingleton {
+ private static final HalRefDoParser INSTANCE = new HalRefDoParser();
+ }
+
+ public static HalRefDoParser getInstance() {
+ return HalRefParserSingleton.INSTANCE;
+ }
+
+ private File getUuidMapConfigFile() {
+ // default file name: hal_uuid_map_config.xml
+ String uuid_map_config_file_name = UUID_MAPPING_CONFIG_PREFIX
+ + SystemProperties.get(PROP_PRODUCT_HARDWARE_SKU, "config")
+ + UUID_MAPPING_CONFIG_EXT;
+ String uuid_map_config_path = null;
+
+ try {
+ // Search in predefined folders
+ for (String path : UUID_MAPPING_CONFIG_PATHS) {
+ uuid_map_config_path = path + uuid_map_config_file_name;
+ File confFile = new File(uuid_map_config_path);
+ if (confFile.exists()) {
+ Log.d(mTag, "UUID mapping config file path: " + uuid_map_config_path);
+ return confFile;
+ }
+ }
+ } catch (Exception e) {
+ Log.e(mTag, "Error in finding UUID mapping config file path: " + uuid_map_config_path);
+ }
+
+ return null;
+ }
+
+ /**
+ * Parses the below mapping structure -
+ *
+ * <ref_do>
+ * <uuid_ref_do>
+ * <uids>
+ * <uid>1000</uid>
+ * </uids>
+ * <uuid>a9b7ba70783b317e9998dc4dd82eb3c5</uuid>
+ * </uuid_ref_do>
+ * </ref_do>
+ */
+ private void parse(InputStream is) {
+ try {
+ XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
+ factory.setNamespaceAware(true);
+ XmlPullParser parser = factory.newPullParser();
+ String text = null;
+ List<Integer> uids = null;
+ byte[] uuid = null;
+
+ parser.setInput(is, null);
+
+ int eventType = parser.getEventType();
+ while (eventType != XmlPullParser.END_DOCUMENT) {
+ String tagname = parser.getName();
+ switch (eventType) {
+ case XmlPullParser.START_TAG:
+ if (tagname.equalsIgnoreCase(UIDS)) {
+ uids = new ArrayList<Integer>();
+ } else if (tagname.equalsIgnoreCase(UUID)) {
+ uuid = null;
+ }
+ break;
+
+ case XmlPullParser.TEXT:
+ text = parser.getText();
+ break;
+
+ case XmlPullParser.END_TAG:
+ if (tagname.equalsIgnoreCase(UUID_REF_DO)) {
+ if (uuid != null) {
+ for (int uid : uids) {
+ mUUIDMap.put(uid, uuid);
+ }
+ }
+ } else if (tagname.equalsIgnoreCase(UID)) {
+ uids.add(Integer.parseInt(text));
+ } else if (tagname.equalsIgnoreCase(UUID)) {
+ byte[] uuidValue = decodeHexUUID(text);
+ uuid = new byte[uuidValue.length + PADDING_BYTES.length];
+ System.arraycopy(PADDING_BYTES, 0, uuid, 0, PADDING_BYTES.length);
+ System.arraycopy(uuidValue, 0, uuid, PADDING_BYTES.length,
+ uuidValue.length);
+
+ }
+ break;
+
+ default:
+ break;
+ }
+ eventType = parser.next();
+ }
+
+ } catch (XmlPullParserException e) {
+ Log.e(mTag, "Error while parsing hal uuid mappings");
+ Log.e(mTag, e.getMessage());
+ } catch (IOException e) {
+ Log.e(mTag, "IO error while parsing hal uuid mappings");
+ Log.e(mTag, e.getMessage());
+ }
+ }
+
+ /**
+ * Finds the uuid mapping config file path from predefined folders
+ * Parses the uuid mapping config file
+ */
+ private void parseUuidMappings() {
+ try {
+ File uuid_map_file = getUuidMapConfigFile();
+ if (uuid_map_file == null) {
+ Log.e(mTag, "Unable to determine UUID mapping config file path");
+ return;
+ }
+
+ parse(new FileInputStream(uuid_map_file));
+ } catch (Exception e) {
+ Log.e(mTag, "Unable to parse hal uuid mappings");
+ Log.e(mTag, e.getMessage());
+ }
+
+ if (DEBUG) {
+ for (Map.Entry<Integer, byte[]> entry : mUUIDMap.entrySet()) {
+ Log.d(mTag, "UID: " + entry.getKey());
+ Log.d(mTag, "UUID: " + Arrays.toString(entry.getValue()));
+ }
+ }
+ }
+
+ /**
+ * Finds UUID for the give UID
+ */
+ public byte[] findUUID(int uid) {
+ return mUUIDMap.get(uid);
+ }
+
+ /**
+ * Convert char to hex digit
+ * @param hexChar
+ * @return hex digit
+ */
+ private int toDigit(char hexChar) {
+ int digit = Character.digit(hexChar, 16);
+ if (digit == -1) {
+ throw new IllegalArgumentException(
+ "Invalid Hexadecimal Character: " + hexChar);
+ }
+ return digit;
+ }
+
+ /**
+ * Convert hex digits string to bytes
+ * @param hextText
+ * @return hex byte
+ */
+ private byte hexToByte(char ch1, char ch2) {
+ int firstDigit = toDigit(ch1);
+ int secondDigit = toDigit(ch2);
+ return (byte) ((firstDigit << 4) + secondDigit);
+ }
+
+ /**
+ * Convert hex string to hex byte array
+ * @param hextText
+ * @return hex bytes
+ */
+ private byte[] decodeHexUUID(String hextText) {
+ if (hextText == null || hextText.length() != 32) {
+ throw new IllegalArgumentException(
+ "Invalid UUID supplied");
+ }
+
+ byte[] bytes = new byte[hextText.length() / 2];
+ for (int i = 0; i < hextText.length(); i += 2) {
+ bytes[i / 2] = hexToByte(hextText.charAt(i), hextText.charAt(i + 1));
+ }
+ return bytes;
+ }
+
+}
diff --git a/src/com/android/se/security/gpac/AID_REF_DO.java b/src/com/android/se/security/gpac/AID_REF_DO.java
index 70bddfb..31764b4 100644
--- a/src/com/android/se/security/gpac/AID_REF_DO.java
+++ b/src/com/android/se/security/gpac/AID_REF_DO.java
@@ -114,7 +114,7 @@ public class AID_REF_DO extends BerTlv {
}
} else if (getTag() == TAG) {
- // sanity checks
+ // quick checks
if ((getValueLength() < 5 || getValueLength() > 16) && getValueLength() != 0) {
throw new ParserException("Invalid value length for AID-REF-DO!");
}
@@ -151,7 +151,7 @@ public class AID_REF_DO extends BerTlv {
stream.write(0x00);
} else if (getTag() == TAG) {
- // sanity check
+ // quick check
if (getValueLength() != 0) {
if (getValueLength() < 5 || getValueLength() > 16) {
throw new DO_Exception("Invalid length of AID!");
diff --git a/src/com/android/se/security/gpac/BerTlv.java b/src/com/android/se/security/gpac/BerTlv.java
index 066bf5e..966a442 100644
--- a/src/com/android/se/security/gpac/BerTlv.java
+++ b/src/com/android/se/security/gpac/BerTlv.java
@@ -225,7 +225,7 @@ public class BerTlv {
/** Returns the byte array of only the data values */
public byte[] getValue() {
- // sanity checks
+ // quick checks
if (mRawData == null
|| mValueLength == 0
|| mValueIndex < 0
diff --git a/src/com/android/se/security/gpac/Hash_REF_DO.java b/src/com/android/se/security/gpac/Hash_REF_DO.java
index edd019a..e131f8b 100644
--- a/src/com/android/se/security/gpac/Hash_REF_DO.java
+++ b/src/com/android/se/security/gpac/Hash_REF_DO.java
@@ -111,7 +111,7 @@ public class Hash_REF_DO extends BerTlv {
int index = getValueIndex();
int length = getValueLength();
- // sanity checks
+ // quick checks
if (length != 0 && length != SHA1_LEN && length != SHA256_LEN) {
throw new ParserException("Invalid value length for Hash-REF-DO!");
}
@@ -139,7 +139,7 @@ public class Hash_REF_DO extends BerTlv {
@Override
public void build(ByteArrayOutputStream stream) throws DO_Exception {
- // sanity checks
+ // quick checks
if (mHash.length != SHA1_LEN && mHash.length != SHA256_LEN && mHash.length != 0) {
throw new DO_Exception("Hash value must be " + SHA1_LEN + " or " + SHA256_LEN
+ " bytes in length!");
diff --git a/src/com/android/se/security/gpac/PERM_AR_DO.java b/src/com/android/se/security/gpac/PERM_AR_DO.java
index f927042..d62862a 100644
--- a/src/com/android/se/security/gpac/PERM_AR_DO.java
+++ b/src/com/android/se/security/gpac/PERM_AR_DO.java
@@ -71,7 +71,7 @@ public class PERM_AR_DO extends BerTlv {
*/
public void build(ByteArrayOutputStream stream) throws DO_Exception {
- // sanity checks
+ // quick checks
if (mPermissionMask.length != PERM_MASK_LEN) {
throw new DO_Exception("Invalid value length for PERM-AR-DO!");
}
diff --git a/src/com/android/se/security/gpac/PKG_REF_DO.java b/src/com/android/se/security/gpac/PKG_REF_DO.java
index a35415a..571909f 100644
--- a/src/com/android/se/security/gpac/PKG_REF_DO.java
+++ b/src/com/android/se/security/gpac/PKG_REF_DO.java
@@ -75,7 +75,7 @@ public class PKG_REF_DO extends BerTlv {
byte[] data = getRawData();
int index = getValueIndex();
- // sanity checks
+ // quick checks
if (getValueLength() > 128) {
throw new ParserException("Invalid value length for PKG-REF-DO!");
}
@@ -98,7 +98,7 @@ public class PKG_REF_DO extends BerTlv {
@Override
public void build(ByteArrayOutputStream stream) throws DO_Exception {
byte[] pkg = mPackageName.getBytes();
- // sanity checks
+ // quick checks
if (pkg.length > 128) {
throw new DO_Exception("Invalid value length for PKG-REF-DO!");
}
diff --git a/tests/unit/Android.bp b/tests/unit/Android.bp
new file mode 100644
index 0000000..497ed09
--- /dev/null
+++ b/tests/unit/Android.bp
@@ -0,0 +1,32 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test {
+ name: "SecureElementInstrumentationTests",
+
+ certificate: "platform",
+
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ "android.test.mock",
+ ],
+
+ static_libs: [
+ "androidx.test.core",
+ "androidx.test.rules",
+ "androidx.test.ext.junit",
+ "mockito-target",
+ "truth-prebuilt",
+ ],
+
+ // Include all test java files.
+ srcs: ["src/**/*.java"],
+
+ platform_apis: true,
+
+ test_suites: ["device-tests"],
+
+ instrumentation_for: "SecureElement",
+}
diff --git a/tests/unit/AndroidManifest.xml b/tests/unit/AndroidManifest.xml
new file mode 100644
index 0000000..eaeb718
--- /dev/null
+++ b/tests/unit/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.se.tests.unit">
+
+ <application android:debuggable="true">
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.se"
+ android:label="SecureElement Test Cases">
+ </instrumentation>
+
+</manifest>
diff --git a/tests/unit/AndroidTest.xml b/tests/unit/AndroidTest.xml
new file mode 100644
index 0000000..c04fec8
--- /dev/null
+++ b/tests/unit/AndroidTest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Runs SecureElement Test Cases.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-instrumentation" />
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+ <option name="force-root" value="true" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="SecureElementInstrumentationTests.apk" />
+ </target_preparer>
+
+ <option name="test-tag" value="SecureElementInstrumentationTests" />
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.se.tests.unit" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ <option name="hidden-api-checks" value="false"/>
+ </test>
+</configuration>
diff --git a/tests/unit/src/com/android/se/SecureElementVendorStableInterfaceFlagTest.java b/tests/unit/src/com/android/se/SecureElementVendorStableInterfaceFlagTest.java
new file mode 100644
index 0000000..68d2907
--- /dev/null
+++ b/tests/unit/src/com/android/se/SecureElementVendorStableInterfaceFlagTest.java
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+package com.android.se;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.IBinder;
+import android.os.ServiceManager;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public final class SecureElementVendorStableInterfaceFlagTest {
+
+ private static final String TAG =
+ SecureElementVendorStableInterfaceFlagTest.class.getSimpleName();
+ public static final String VSTABLE_SECURE_ELEMENT_SERVICE =
+ "android.se.omapi.ISecureElementService/default";
+ private Context mContext;
+
+ @Before
+ public void setUp() {
+ mContext = InstrumentationRegistry.getTargetContext();
+ PackageManager pm = mContext.getPackageManager();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+
+ @Test
+ public void testIsVendorStableInterfaceEnabled() {
+ boolean secure_element_vintf_enabled =
+ mContext.getResources().getBoolean(R.bool.secure_element_vintf_enabled);
+
+ IBinder binder = ServiceManager.getService(VSTABLE_SECURE_ELEMENT_SERVICE);
+ if (secure_element_vintf_enabled) {
+ Assert.assertNotNull(binder);
+ } else {
+ Assert.assertNull(binder);
+ }
+
+ }
+}