diff options
author | Yerriswamy <yerriswamy.kurubathayanna@nxp.com> | 2020-04-14 08:08:39 +0530 |
---|---|---|
committer | nxf24591 <nanjesh.s_1@nxp.com> | 2020-05-01 00:48:12 +0530 |
commit | ab9a0f5a76f1d899109c7b61b024c9f5fe39dc19 (patch) | |
tree | 90631f3ea4c38dad19bbed13e16c26c85d59f7f6 | |
parent | 1531c0ac5af79fa2f7eaea7ad66cb852c47f465c (diff) |
{R-DP1} Support configurable AIDs for ARAM
1. Try to retrieve ARs from a configurable list of AIDs.
If all AIDs are not accessible, then try default AID.
2. Add PKG_REF_DO/PERM_AR_DO for AR parsing.
Bug:139078767
Test: Access rules could be retrieved from different AIDs.
-rw-r--r-- | res/values/config.xml | 6 | ||||
-rwxr-xr-x | src/com/android/se/Terminal.java | 4 | ||||
-rwxr-xr-x | src/com/android/se/security/AccessControlEnforcer.java | 13 | ||||
-rw-r--r-- | src/com/android/se/security/ara/AraController.java | 51 | ||||
-rwxr-xr-x | src/com/android/se/security/gpac/AR_DO.java | 44 | ||||
-rw-r--r-- | src/com/android/se/security/gpac/PERM_AR_DO.java | 88 | ||||
-rw-r--r-- | src/com/android/se/security/gpac/PKG_REF_DO.java | 143 | ||||
-rw-r--r-- | src/com/android/se/security/gpac/REF_DO.java | 55 |
8 files changed, 387 insertions, 17 deletions
diff --git a/res/values/config.xml b/res/values/config.xml new file mode 100644 index 0000000..cc310a0 --- /dev/null +++ b/res/values/config.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <!-- 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" /> +</resources> diff --git a/src/com/android/se/Terminal.java b/src/com/android/se/Terminal.java index 6daee46..45b02ac 100755 --- a/src/com/android/se/Terminal.java +++ b/src/com/android/se/Terminal.java @@ -804,6 +804,10 @@ public class Terminal { return mAccessControlEnforcer; } + public Context getContext() { + return mContext; + } + /** Dump data for debug purpose . */ public void dump(PrintWriter writer) { writer.println("SECURE ELEMENT SERVICE TERMINAL: " + mName); diff --git a/src/com/android/se/security/AccessControlEnforcer.java b/src/com/android/se/security/AccessControlEnforcer.java index 79252bd..a4ceb70 100755 --- a/src/com/android/se/security/AccessControlEnforcer.java +++ b/src/com/android/se/security/AccessControlEnforcer.java @@ -84,7 +84,10 @@ public class AccessControlEnforcer { mAccessRuleCache = new AccessRuleCache(); } - public static byte[] getDefaultAccessControlAid() { + public byte[] getDefaultAccessControlAid() { + if (mAraController != null) { + return mAraController.getAccessControlAid(); + } return AraController.getAraMAid(); } @@ -454,6 +457,14 @@ public class AccessControlEnforcer { writer.println("mUseArf: " + mUseArf); writer.println("mUseAra: " + mUseAra); + if (mUseAra && mAraController != null) { + if (getDefaultAccessControlAid() == null) { + writer.println("AraInUse: default applet"); + } else { + writer.println("AraInUse: " + ByteArrayConverter.byteArrayToHexString( + getDefaultAccessControlAid())); + } + } writer.println("mInitialChannelAccess:"); writer.println(mInitialChannelAccess.toString()); writer.println(); diff --git a/src/com/android/se/security/ara/AraController.java b/src/com/android/se/security/ara/AraController.java index bc4ea19..52223b6 100644 --- a/src/com/android/se/security/ara/AraController.java +++ b/src/com/android/se/security/ara/AraController.java @@ -35,10 +35,15 @@ package com.android.se.security.ara; +import android.content.Context; +import android.text.TextUtils; import android.util.Log; import com.android.se.Channel; +import com.android.se.R; +import com.android.se.SecureElementService; import com.android.se.Terminal; +import com.android.se.internal.ByteArrayConverter; import com.android.se.security.AccessRuleCache; import com.android.se.security.ChannelAccess; import com.android.se.security.gpac.BerTlv; @@ -73,27 +78,65 @@ public class AraController { private AccessRuleCache mAccessRuleCache = null; private Terminal mTerminal = null; private AccessRuleApplet mApplet = null; + private Context mContext = null; + private String[] mAids = new String[0]; + private byte[] mAccessControlAid = ARA_M_AID; public AraController(AccessRuleCache cache, Terminal terminal) { mAccessRuleCache = cache; mTerminal = terminal; + mContext = mTerminal.getContext(); + if (mTerminal.getName().startsWith(SecureElementService.ESE_TERMINAL)) { + mAids = mContext.getResources().getStringArray( + R.array.config_ara_aid_candidate_list_ese); + } } public static byte[] getAraMAid() { return ARA_M_AID; } + public byte[] getAccessControlAid() { + return mAccessControlAid; + } + /** * Initialize the AraController, reads the refresh tag. * and fetch the access rules */ public synchronized void initialize() throws IOException, NoSuchElementException { - Channel channel = mTerminal.openLogicalChannelWithoutChannelAccess(getAraMAid()); + Channel channel = null; + byte[] aid = null; + + // try to fetch access rules from ARA Aid list + for (String araAid : mAids) { + if (!TextUtils.isEmpty(araAid)) { + aid = ByteArrayConverter.hexStringToByteArray(araAid); + } else { + aid = null; + } + try { + channel = mTerminal.openLogicalChannelWithoutChannelAccess(aid); + if (channel == null) { + throw new MissingResourceException("could not open channel", "", ""); + } + mAccessControlAid = aid; + break; + } catch (NoSuchElementException e) { + Log.i(mTag, "applet:" + araAid + " is not accessible"); + continue; + } + } + + // try to fetch access rules from ARA-M if all ARA in Aid list is not accessible if (channel == null) { - throw new MissingResourceException("could not open channel", "", ""); + channel = mTerminal.openLogicalChannelWithoutChannelAccess(getAraMAid()); + if (channel == null) { + throw new MissingResourceException("could not open channel", "", ""); + } } - // set access conditions to access ARA-M. + // set access conditions to access ARA. ChannelAccess araChannelAccess = new ChannelAccess(); araChannelAccess.setAccess(ChannelAccess.ACCESS.ALLOWED, ""); araChannelAccess.setApduAccess(ChannelAccess.ACCESS.ALLOWED); @@ -104,7 +147,7 @@ public class AraController { mApplet = new AccessRuleApplet(channel); byte[] tag = mApplet.readRefreshTag(); // if refresh tag is equal to the previous one it is not - // neccessary to read all rules again. + // necessary to read all rules again. if (mAccessRuleCache.isRefreshTagEqual(tag)) { Log.i(mTag, "Refresh tag unchanged. Using access rules from cache."); return; diff --git a/src/com/android/se/security/gpac/AR_DO.java b/src/com/android/se/security/gpac/AR_DO.java index ebb5a6e..491b099 100755 --- a/src/com/android/se/security/gpac/AR_DO.java +++ b/src/com/android/se/security/gpac/AR_DO.java @@ -49,15 +49,31 @@ public class AR_DO extends BerTlv { private APDU_AR_DO mApduAr = null; private NFC_AR_DO mNfcAr = null; + private PERM_AR_DO mPermAr = null; public AR_DO(byte[] rawData, int valueIndex, int valueLength) { super(rawData, TAG, valueIndex, valueLength); } + public AR_DO(APDU_AR_DO apduArDo, NFC_AR_DO nfcArDo, PERM_AR_DO permArDo) { + super(null, TAG, 0, 0); + mApduAr = apduArDo; + mNfcAr = nfcArDo; + mPermAr = permArDo; + } + public AR_DO(APDU_AR_DO apduArDo, NFC_AR_DO nfcArDo) { super(null, TAG, 0, 0); mApduAr = apduArDo; mNfcAr = nfcArDo; + mPermAr = null; + } + + public AR_DO(PERM_AR_DO permArDo) { + super(null, TAG, 0, 0); + mApduAr = null; + mNfcAr = null; + mPermAr = permArDo; } public APDU_AR_DO getApduArDo() { @@ -68,19 +84,27 @@ public class AR_DO extends BerTlv { return mNfcAr; } + public PERM_AR_DO getPermArDo() { + return mPermAr; + } + @Override /** * Interpret value. * * <p>Tag: E3 * - * <p>Value: Value can contain APDU-AR-DO or NFC-AR-DO or APDU-AR-DO | NFC-AR-DO A concatenation - * of one or two AR-DO(s). If two AR-DO(s) are present these must have different types. + * <p>Value: + * 1. Value can contain APDU-AR-DO or NFC-AR-DO or APDU-AR-DO | NFC-AR-DO A + * concatenation of one or two AR-DO(s). If two AR-DO(s) are present these must have + * different types. + * 2. PERM-AR-DO */ public void interpret() throws ParserException { this.mApduAr = null; this.mNfcAr = null; + this.mPermAr = null; byte[] data = getRawData(); int index = getValueIndex(); @@ -98,6 +122,9 @@ public class AR_DO extends BerTlv { } else if (temp.getTag() == NFC_AR_DO.TAG) { // NFC-AR-DO mNfcAr = new NFC_AR_DO(data, temp.getValueIndex(), temp.getValueLength()); mNfcAr.interpret(); + } else if (temp.getTag() == PERM_AR_DO.TAG) { // PERM-AR-DO + mPermAr = new PERM_AR_DO(data, temp.getValueIndex(), temp.getValueLength()); + mPermAr.interpret(); } else { // un-comment following line if a more restrictive // behavior is necessary. @@ -106,7 +133,7 @@ public class AR_DO extends BerTlv { index = temp.getValueIndex() + temp.getValueLength(); } while (getValueIndex() + getValueLength() > index); - if (mApduAr == null && mNfcAr == null) { + if (mApduAr == null && mNfcAr == null && mPermAr == null) { throw new ParserException("No valid DO in AR-DO!"); } } @@ -117,8 +144,11 @@ public class AR_DO extends BerTlv { * * <p>Tag: E3 * - * <p>Value: Value can contain APDU-AR-DO or NFC-AR-DO or APDU-AR-DO | NFC-AR-DO A concatenation - * of one or two AR-DO(s). If two AR-DO(s) are present these must have different types. + * <p>Value: + * 1. Value can contain APDU-AR-DO or NFC-AR-DO or APDU-AR-DO | NFC-AR-DO A + * concatenation of one or two AR-DO(s). If two AR-DO(s) are present these must have + * different types. + * 2. PERM-AR-DO */ public void build(ByteArrayOutputStream stream) throws DO_Exception { @@ -134,6 +164,10 @@ public class AR_DO extends BerTlv { mNfcAr.build(temp); } + if (mPermAr != null) { + mPermAr.build(temp); + } + BerTlv.encodeLength(temp.size(), stream); try { stream.write(temp.toByteArray()); diff --git a/src/com/android/se/security/gpac/PERM_AR_DO.java b/src/com/android/se/security/gpac/PERM_AR_DO.java new file mode 100644 index 0000000..f927042 --- /dev/null +++ b/src/com/android/se/security/gpac/PERM_AR_DO.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2019 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.gpac; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +/** + * PERM-AR-DO: The access rule for Device API control consists of a permission bit mask of 8 bytes. + */ +public class PERM_AR_DO extends BerTlv { + + public static final int TAG = 0xDB; + + public static final int PERM_MASK_LEN = 8; + + private byte[] mPermissionMask = new byte[0]; + + public PERM_AR_DO(byte[] rawData, int valueIndex, int valueLength) { + super(rawData, TAG, valueIndex, valueLength); + } + + public PERM_AR_DO(byte[] permissionMask) { + super(permissionMask, TAG, 0, (permissionMask == null ? 0 : permissionMask.length)); + if (permissionMask != null) mPermissionMask = permissionMask; + } + + public byte[] getPermissionMask() { + return mPermissionMask; + } + + @Override + /** + * Tag: DB Length: 8 Value: Contains a permission mask + */ + public void interpret() throws ParserException { + mPermissionMask = new byte[0]; + + byte[] data = getRawData(); + int index = getValueIndex(); + int length = getValueLength(); + + if (index + getValueLength() > data.length) { + throw new ParserException("Not enough data for PERM-AR-DO!"); + } + + if (length == PERM_MASK_LEN) { + mPermissionMask = new byte[length]; + System.arraycopy(data, index, mPermissionMask, 0, length); + } else { + throw new ParserException("Invalid length of PERM-AR-DO!"); + } + } + + @Override + /** + * Tag: DB Length: 8 Value: Contains a permission mask + */ + public void build(ByteArrayOutputStream stream) throws DO_Exception { + + // sanity checks + if (mPermissionMask.length != PERM_MASK_LEN) { + throw new DO_Exception("Invalid value length for PERM-AR-DO!"); + } + + // write tag + stream.write(getTag()); + try { + stream.write(mPermissionMask.length); + stream.write(mPermissionMask); + } catch (IOException ioe) { + throw new DO_Exception("PERM could not be written!"); + } + } +} diff --git a/src/com/android/se/security/gpac/PKG_REF_DO.java b/src/com/android/se/security/gpac/PKG_REF_DO.java new file mode 100644 index 0000000..a35415a --- /dev/null +++ b/src/com/android/se/security/gpac/PKG_REF_DO.java @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2018 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.gpac; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Arrays; + +/** + * PKG-REF-DO: The PKG-REF-DO is used for retrieving and storing the corresponding access rules + * for a device application (which is identified by the package name) from and to + * the ARA + */ +public class PKG_REF_DO extends BerTlv { + + public static final int TAG = 0xCA; + + private String mPackageName = null; + + public PKG_REF_DO(byte[] rawData, int valueIndex, int valueLength) { + super(rawData, TAG, valueIndex, valueLength); + } + + public PKG_REF_DO(byte[] pkg) { + super(pkg, TAG, 0, (pkg == null ? 0 : pkg.length)); + if (pkg != null) { + mPackageName = new String(pkg); + } + } + + public PKG_REF_DO() { + super(null, TAG, 0, 0); + } + + /** + * Comapares two PKG_REF_DO objects and returns true if they are equal + */ + public static boolean equals(PKG_REF_DO obj1, PKG_REF_DO obj2) { + if (obj1 == null) { + return (obj2 == null) ? true : false; + } + return obj1.equals(obj2); + } + + public String getPackageName() { + return mPackageName; + } + + @Override + public String toString() { + return new String("PKG_REF_DO: " + mPackageName); + } + + /** + * Tags: CA Length: max length is 128 bytes + * + * <p>Value: pkg: identifies ASCII encoded package name + * + */ + @Override + public void interpret() throws ParserException { + byte[] data = getRawData(); + int index = getValueIndex(); + + // sanity checks + if (getValueLength() > 128) { + throw new ParserException("Invalid value length for PKG-REF-DO!"); + } + + if (index + getValueLength() > data.length) { + throw new ParserException("Not enough data for PKG-REF-DO!"); + } + + byte[] pkg = new byte[getValueLength()]; + System.arraycopy(data, index, pkg, 0, getValueLength()); + mPackageName = new String(pkg); + } + + /** + * Tags: CA Length: max length is 128 bytes + * + * <p>Value: pkg: identifies ASCII encoded package name + * + */ + @Override + public void build(ByteArrayOutputStream stream) throws DO_Exception { + byte[] pkg = mPackageName.getBytes(); + // sanity checks + if (pkg.length > 128) { + throw new DO_Exception("Invalid value length for PKG-REF-DO!"); + } + + stream.write(getTag()); + + try { + stream.write(pkg.length); + stream.write(pkg); + } catch (IOException ioe) { + throw new DO_Exception("PKG could not be written!"); + } + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof PKG_REF_DO) { + PKG_REF_DO pkg_ref_do = (PKG_REF_DO) obj; + if (getTag() == pkg_ref_do.getTag()) { + if (mPackageName != null) { + return mPackageName.equals(pkg_ref_do.mPackageName); + } else { + return (pkg_ref_do.mPackageName == null); + } + } + } + return false; + } + + @Override + public int hashCode() { + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + try { + this.build(stream); + } catch (DO_Exception e) { + return 1; + } + byte[] data = stream.toByteArray(); + int hash = Arrays.hashCode(data); + return hash; + } +} diff --git a/src/com/android/se/security/gpac/REF_DO.java b/src/com/android/se/security/gpac/REF_DO.java index 7ccf547..0400e96 100644 --- a/src/com/android/se/security/gpac/REF_DO.java +++ b/src/com/android/se/security/gpac/REF_DO.java @@ -47,15 +47,24 @@ public class REF_DO extends BerTlv { private AID_REF_DO mAidDo = null; private Hash_REF_DO mHashDo = null; + private PKG_REF_DO mPkgDo = null; public REF_DO(byte[] rawData, int valueIndex, int valueLength) { super(rawData, TAG, valueIndex, valueLength); } + public REF_DO(AID_REF_DO aidRefDo, Hash_REF_DO hashRefDo, PKG_REF_DO pkgRefDo) { + super(null, TAG, 0, 0); + mAidDo = aidRefDo; + mHashDo = hashRefDo; + mPkgDo = pkgRefDo; + } + public REF_DO(AID_REF_DO aidRefDo, Hash_REF_DO hashRefDo) { super(null, TAG, 0, 0); mAidDo = aidRefDo; mHashDo = hashRefDo; + mPkgDo = null; } @Override @@ -68,6 +77,10 @@ public class REF_DO extends BerTlv { } if (mHashDo != null) { b.append(mHashDo.toString()); + b.append(' '); + } + if (mPkgDo != null) { + b.append(mPkgDo.toString()); } return b.toString(); } @@ -80,12 +93,19 @@ public class REF_DO extends BerTlv { return mHashDo; } + public PKG_REF_DO getPkgDo() { + return mPkgDo; + } + /** * Interpret data. * * <p>Tags: E1 -> Length: n * - * <p>Value: AID-REF-DO | Hash-REF-DO: A concatenation of an AID-REF-DO and a Hash-REF-DO. + * <p>Value: + * 1. AID-REF-DO | Hash-REF-DO: A concatenation of an AID-REF-DO and a Hash-REF-DO. + * 2. Hash-REF-DO or Hash-REF-DO | PKG-REF-DO A concatenation of a Hash-REF-DO and a + * PKG-REF-DO. * * <p>Length: n bytes. */ @@ -94,6 +114,7 @@ public class REF_DO extends BerTlv { mAidDo = null; mHashDo = null; + mPkgDo = null; byte[] data = getRawData(); int index = getValueIndex(); @@ -113,6 +134,9 @@ public class REF_DO extends BerTlv { } else if (temp.getTag() == Hash_REF_DO.TAG) { // Hash-REF-DO mHashDo = new Hash_REF_DO(data, temp.getValueIndex(), temp.getValueLength()); mHashDo.interpret(); + } else if (temp.getTag() == PKG_REF_DO.TAG) { // PKG-REF-DO + mPkgDo = new PKG_REF_DO(data, temp.getValueIndex(), temp.getValueLength()); + mPkgDo.interpret(); } else { // uncomment following line if a more restrictive // behaviour is necessary. @@ -121,6 +145,10 @@ public class REF_DO extends BerTlv { index = temp.getValueIndex() + temp.getValueLength(); } while (getValueIndex() + getValueLength() > index); + if (mAidDo != null && !mAidDo.isCarrierPrivilege() && mHashDo != null && mPkgDo != null) { + throw new ParserException("Unexpected combination of SEAC DOs and DAC DO"); + } + // A rule without AID is a Carrier Privilege Rule. // Enforces the AID to be the Carrier Privilege AID to avoid a null AID. if (mAidDo == null && mHashDo != null) { @@ -138,19 +166,30 @@ public class REF_DO extends BerTlv { } /** - * Tag: E1 Length: n Value: AID-REF-DO | Hash-REF-DO: A concatenation of an AID-REF-DO and a - * Hash-REF-DO. + * Tag: E1 Length: n Value: + * 1. AID-REF-DO | Hash-REF-DO: A concatenation of an AID-REF-DO and a Hash-REF-DO. + * 2. Hash-REF-DO or Hash-REF-DO | PKG-REF-DO A concatenation of a Hash-REF-DO and a + * PKG-REF-DO. */ @Override public void build(ByteArrayOutputStream stream) throws DO_Exception { ByteArrayOutputStream temp = new ByteArrayOutputStream(); - if (mAidDo == null || mHashDo == null) { + if (mHashDo == null) { throw new DO_Exception("REF-DO: Required DO missing!"); } - mAidDo.build(temp); - mHashDo.build(temp); + if (mAidDo != null) { + mAidDo.build(temp); + } + + if (mHashDo != null) { + mHashDo.build(temp); + } + + if (mPkgDo != null) { + mPkgDo.build(temp); + } byte[] data = temp.toByteArray(); BerTlv tlv = new BerTlv(data, getTag(), 0, data.length); @@ -164,7 +203,9 @@ public class REF_DO extends BerTlv { if (getTag() == ref_do.getTag()) { if (AID_REF_DO.equals(mAidDo, ref_do.mAidDo)) { if (Hash_REF_DO.equals(mHashDo, ref_do.mHashDo)) { - return true; + if (PKG_REF_DO.equals(mPkgDo, ref_do.mPkgDo)) { + return true; + } } } } |