summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrajesh.nyamagoud <nyamagoud@google.com>2021-11-23 06:00:31 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2021-11-23 06:00:31 +0000
commite0808a31dc8239d74f0ae0e66a2ff0ca1422ed85 (patch)
tree557723747884587579a8dc47165b90811a4cabfd
parentcbaf5356e26b3949f1b9b297e3390b0f7ddd29a2 (diff)
parent6085656b8d3676ab0234b5ce07b75f3b045d57f2 (diff)
downloadSecureElement-e0808a31dc8239d74f0ae0e66a2ff0ca1422ed85.tar.gz
UUID based access rules support for SE am: 10b0a90cc7 am: 22aa6a4fc9 am: a25fa592a6 am: 6085656b8d
Original change: https://android-review.googlesource.com/c/platform/packages/apps/SecureElement/+/1769148 Change-Id: I8ca7b33fac9c9ed50823c4e3bc46f5b7bad8b55a
-rw-r--r--etc/hal_uuid_map_config.xml41
-rw-r--r--src/com/android/se/SecureElementService.java47
-rw-r--r--src/com/android/se/Terminal.java65
-rw-r--r--src/com/android/se/security/AccessControlEnforcer.java21
-rw-r--r--src/com/android/se/security/HalRefDoParser.java250
5 files changed, 395 insertions, 29 deletions
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/src/com/android/se/SecureElementService.java b/src/com/android/se/SecureElementService.java
index 38899fa..c7187e1 100644
--- a/src/com/android/se/SecureElementService.java
+++ b/src/com/android/se/SecureElementService.java
@@ -45,6 +45,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;
@@ -244,6 +245,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;
@@ -326,12 +337,26 @@ 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");
+ 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) {
@@ -368,12 +393,26 @@ 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");
+ 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) {
diff --git a/src/com/android/se/Terminal.java b/src/com/android/se/Terminal.java
index d97dd2f..1c055a0 100644
--- a/src/com/android/se/Terminal.java
+++ b/src/com/android/se/Terminal.java
@@ -32,6 +32,7 @@ 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;
@@ -432,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;
@@ -446,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) {
@@ -516,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;
@@ -541,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) {
@@ -745,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
@@ -764,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();
@@ -794,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;
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;
+ }
+
+}