Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 72d28cd5 authored by Cassie Han's avatar Cassie Han Committed by Gerrit Code Review
Browse files

Merge "Retrieve and interpret ODF, DODF and ACMF to find the correct path of ACRF."

parents 9f2802fe f3eae6c5
Loading
Loading
Loading
Loading
+163 −8
Original line number Diff line number Diff line
@@ -53,7 +53,7 @@ public class UiccPkcs15 extends Handler {
    private class FileHandler extends Handler {
        // EF path for PKCS15 root, eg. "3F007F50"
        // null if logical channel is used for PKCS15 access.
        private final String mPkcs15Path;
        final String mPkcs15Path;
        // Message to send when file has been parsed.
        private Message mCallback;
        // File id to read data from, eg. "5031"
@@ -90,7 +90,7 @@ public class UiccPkcs15 extends Handler {
        private void readBinary() {
            if (mChannelId >=0 ) {
                mUiccProfile.iccTransmitApduLogicalChannel(mChannelId, 0x00, 0xB0, 0x00, 0x00, 0x00,
                        "", obtainMessage(EVENT_READ_BINARY_DONE));
                        mFileId, obtainMessage(EVENT_READ_BINARY_DONE));
            } else {
                log("EF based");
            }
@@ -200,8 +200,8 @@ public class UiccPkcs15 extends Handler {
                    // ar.result is null if using logical channel,
                    // or string for pkcs15 path if using file access.
                    mFh = new FileHandler((String) ar.result);
                    if (!mFh.loadFile(ID_ACRF, obtainMessage(EVENT_LOAD_ACRF_DONE))) {
                        cleanUp();
                    if (!mFh.loadFile(EFODF_PATH, obtainMessage(EVENT_LOAD_ODF_DONE))) {
                        startFromAcrf();
                    }
                } else {
                    log("select pkcs15 failed: " + ar.exception);
@@ -210,6 +210,39 @@ public class UiccPkcs15 extends Handler {
                }
                break;

            case EVENT_LOAD_ODF_DONE:
                if (ar.exception == null && ar.result != null) {
                    String idDodf = parseOdf((String) ar.result);
                    if (!mFh.loadFile(idDodf, obtainMessage(EVENT_LOAD_DODF_DONE))) {
                        startFromAcrf();
                    }
                } else {
                    startFromAcrf();
                }
                break;

            case EVENT_LOAD_DODF_DONE:
                if (ar.exception == null && ar.result != null) {
                    String idAcmf = parseDodf((String) ar.result);
                    if (!mFh.loadFile(idAcmf, obtainMessage(EVENT_LOAD_ACMF_DONE))) {
                        startFromAcrf();
                    }
                } else {
                    startFromAcrf();
                }
                break;

            case EVENT_LOAD_ACMF_DONE:
                if (ar.exception == null && ar.result != null) {
                    String idAcrf = parseAcmf((String) ar.result);
                    if (!mFh.loadFile(idAcrf, obtainMessage(EVENT_LOAD_ACRF_DONE))) {
                        startFromAcrf();
                    }
                } else {
                    startFromAcrf();
                }
                break;

            case EVENT_LOAD_ACRF_DONE:
                if (ar.exception == null && ar.result != null) {
                    mRules = new ArrayList<String>();
@@ -238,6 +271,13 @@ public class UiccPkcs15 extends Handler {
        }
    }

    private void startFromAcrf() {
        log("Fallback to use ACRF_PATH");
        if (!mFh.loadFile(ACRF_PATH, obtainMessage(EVENT_LOAD_ACRF_DONE))) {
            cleanUp();
        }
    }

    private void cleanUp() {
        log("cleanUp");
        if (mChannelId >= 0) {
@@ -250,10 +290,125 @@ public class UiccPkcs15 extends Handler {

    // Constants defined in specs, needed for parsing
    private static final String CARRIER_RULE_AID = "FFFFFFFFFFFF"; // AID for carrier privilege rule
    private static final String ID_ACRF = "4300";
    private static final String ACRF_PATH = "4300";
    private static final String EFODF_PATH = "5031";
    private static final String TAG_ASN_SEQUENCE = "30";
    private static final String TAG_ASN_OCTET_STRING = "04";
    private static final String TAG_ASN_OID = "06";
    private static final String TAG_TARGET_AID = "A0";
    private static final String TAG_ODF = "A7";
    private static final String TAG_DODF = "A1";
    private static final String REFRESH_TAG_LEN = "08";
    // OID defined by Global Platform for the "Access Control". The hexstring here can be converted
    // to OID string value 1.2.840.114283.200.1.1
    public static final String AC_OID = "060A2A864886FC6B81480101";


    // parse ODF file to get file id for DODF file
    // data is hex string, return file id if parse success, null otherwise
    private String parseOdf(String data) {
        // Example:
        // [A7] 06 [30] 04 [04] 02 52 07
        try {
            TLV tlvRule = new TLV(TAG_ODF); // A7
            tlvRule.parse(data, false);
            String ruleString = tlvRule.getValue();
            TLV tlvAsnPath = new TLV(TAG_ASN_SEQUENCE); // 30
            TLV tlvPath = new TLV(TAG_ASN_OCTET_STRING);  // 04
            tlvAsnPath.parse(ruleString, true);
            tlvPath.parse(tlvAsnPath.getValue(), true);
            return tlvPath.getValue();
        } catch (IllegalArgumentException | IndexOutOfBoundsException ex) {
            log("Error: " + ex);
            return null;
        }
    }

    // parse DODF file to get file id for ACMF file
    // data is hex string, return file id if parse success, null otherwise
    private String parseDodf(String data) {
        // Example:
        // [A1] 29 [30] 00 [30] 0F 0C 0D 47 50 20 53 45 20 41 63 63 20 43 74 6C [A1] 14 [30] 12
        // [06] 0A 2A 86 48 86 FC 6B 81 48 01 01 [30] 04 04 02 42 00
        String ret = null;
        String acRules = data;
        while (!acRules.isEmpty()) {
            TLV dodfTag = new TLV(TAG_DODF); // A1
            try {
                acRules = dodfTag.parse(acRules, false);
                String ruleString = dodfTag.getValue();
                // Skip the Common Object Attributes
                TLV commonObjectAttributes = new TLV(TAG_ASN_SEQUENCE); // 30
                ruleString = commonObjectAttributes.parse(ruleString, false);

                // Skip the Common Data Object Attributes
                TLV commonDataObjectAttributes = new TLV(TAG_ASN_SEQUENCE); // 30
                ruleString = commonDataObjectAttributes.parse(ruleString, false);

                if (ruleString.startsWith(TAG_TARGET_AID)) {
                    // Skip SubClassAttributes [Optional]
                    TLV subClassAttributes = new TLV(TAG_TARGET_AID); // A0
                    ruleString = subClassAttributes.parse(ruleString, false);
                }

                if (ruleString.startsWith(TAG_DODF)) {
                    TLV oidDoTag = new TLV(TAG_DODF); // A1
                    oidDoTag.parse(ruleString, true);
                    ruleString = oidDoTag.getValue();

                    TLV oidDo = new TLV(TAG_ASN_SEQUENCE); // 30
                    oidDo.parse(ruleString, true);
                    ruleString = oidDo.getValue();

                    TLV oidTag = new TLV(TAG_ASN_OID); // 06
                    oidTag.parse(ruleString, false);
                    // Example : [06] 0A 2A 86 48 86 FC 6B 81 48 01 01
                    String oid = oidTag.getValue();
                    if (oid.equals(AC_OID)) {
                        // Skip OID and get the AC to the ACCM
                        ruleString = oidTag.parse(ruleString, false);
                        TLV tlvAsnPath = new TLV(TAG_ASN_SEQUENCE); // 30
                        TLV tlvPath = new TLV(TAG_ASN_OCTET_STRING);  // 04
                        tlvAsnPath.parse(ruleString, true);
                        tlvPath.parse(tlvAsnPath.getValue(), true);
                        return tlvPath.getValue();
                    }
                }
                continue; // skip current rule as it doesn't have expected TAG
            } catch (IllegalArgumentException | IndexOutOfBoundsException ex) {
                log("Error: " + ex);
                break; // Bad data, ignore all remaining ACRules
            }
        }
        return ret;
    }

    // parse ACMF file to get file id for ACRF file
    // data is hex string, return file id if parse success, null otherwise
    private String parseAcmf(String data) {
        try {
            // [30] 10 [04] 08 01 02 03 04 05 06 07 08 [30] 04 [04] 02 43 00
            TLV acmfTag = new TLV(TAG_ASN_SEQUENCE); // 30
            acmfTag.parse(data, false);
            String ruleString = acmfTag.getValue();
            TLV refreshTag = new TLV(TAG_ASN_OCTET_STRING); // 04
            String refreshTagLength = refreshTag.parseLength(ruleString);
            if (!refreshTagLength.equals(REFRESH_TAG_LEN)) {
                log("Error: refresh tag in ACMF must be 8.");
                return null;
            }
            ruleString = refreshTag.parse(ruleString, false);
            TLV tlvAsnPath = new TLV(TAG_ASN_SEQUENCE); // 30
            TLV tlvPath = new TLV(TAG_ASN_OCTET_STRING);  // 04
            tlvAsnPath.parse(ruleString, true);
            tlvPath.parse(tlvAsnPath.getValue(), true);
            return tlvPath.getValue();
        } catch (IllegalArgumentException | IndexOutOfBoundsException ex) {
            log("Error: " + ex);
            return null;
        }

    }

    // parse ACRF file to get file id for ACCF file
    // data is hex string, return file id if parse success, null otherwise
@@ -262,14 +417,14 @@ public class UiccPkcs15 extends Handler {

        String acRules = data;
        while (!acRules.isEmpty()) {
            // Example:
            // [30] 10 [A0] 08 04 06 FF FF FF FF FF FF [30] 04 [04] 02 43 10
            // bytes in [] are tags for the data
            TLV tlvRule = new TLV(TAG_ASN_SEQUENCE);
            try {
                acRules = tlvRule.parse(acRules, false);
                String ruleString = tlvRule.getValue();
                if (ruleString.startsWith(TAG_TARGET_AID)) {
                    // rule string consists of target AID + path, example:
                    // [A0] 08 [04] 06 FF FF FF FF FF FF [30] 04 [04] 02 43 10
                    // bytes in [] are tags for the data
                    TLV tlvTarget = new TLV(TAG_TARGET_AID); // A0
                    TLV tlvAid = new TLV(TAG_ASN_OCTET_STRING); // 04
                    TLV tlvAsnPath = new TLV(TAG_ASN_SEQUENCE); // 30
+285 −5
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import static org.mockito.Mockito.doAnswer;
import android.content.pm.Signature;
import android.os.AsyncResult;
import android.os.Message;
import android.telephony.UiccAccessRule;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -41,11 +42,17 @@ import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;

import java.util.List;

@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class UiccCarrierPrivilegeRulesTest extends TelephonyTest {
    private UiccCarrierPrivilegeRules mUiccCarrierPrivilegeRules;

    private static final String ARAM = "A00000015141434C00";
    private static final String ARAD = "A00000015144414300";
    private static final String PKCS15_AID = "A000000063504B43532D3135";

    @Mock
    private UiccProfile mUiccProfile;

@@ -289,10 +296,6 @@ public class UiccCarrierPrivilegeRulesTest extends TelephonyTest {
        assertTrue(!mUiccCarrierPrivilegeRules.shouldRetry(ar, 0));
    }

    private static final String ARAM = "A00000015141434C00";
    private static final String ARAD = "A00000015144414300";
    private static final String PKCS15_AID = "A000000063504B43532D3135";

    @Test
    @SmallTest
    public void testAID_OnlyARAM() {
@@ -476,7 +479,7 @@ public class UiccCarrierPrivilegeRulesTest extends TelephonyTest {

    @Test
    @SmallTest
    public void testAID_NeitherARAMorARAD() {
    public void testAID_ARFFailed() {
        final String hexString =
                "FF4045E243E135C114ABCD92CBB156B280FA4E1429A6ECEEB6E5C1BFE4CA1D636F6D2E676F6F676"
                        + "C652E616E64726F69642E617070732E6D79617070E30ADB080000000000000001";
@@ -515,8 +518,285 @@ public class UiccCarrierPrivilegeRulesTest extends TelephonyTest {
        assertTrue(!mUiccCarrierPrivilegeRules.hasCarrierPrivilegeRules());
    }

    @Test
    @SmallTest
    public void testAID_ARFSucceed() {
        /**
         * PKCS#15 application (AID: A0 00 00 00 63 50 4B 43 53 2D 31 35)
         *   -ODF (5031)
         *       A7 06 30 04 04 02 52 07
         *   -DODF (5207)
         *       A1 29 30 00 30 0F 0C 0D 47 50 20 53 45 20 41 63 63 20 43 74 6C A1 14 30 12
         *       06 0A 2A 86 48 86 FC 6B 81 48 01 01 30 04 04 02 42 00
         *   -EF ACMain (4200)
         *       30 10 04 08 01 02 03 04 05 06 07 08 30 04 04 02 43 00
         *   -EF ACRules (4300)
         *       30 10 A0 08 04 06 A0 00 00 01 51 01 30 04 04 02 43 10
         *   -EF ACConditions1 (4310)
         *       30 22
         *          04 20
         *             B9CFCE1C47A6AC713442718F15EF55B00B3A6D1A6D48CB46249FA8EB51465350
         *       30 22
         *          04 20
         *             4C36AF4A5BDAD97C1F3D8B283416D244496C2AC5EAFE8226079EF6F676FD1859
         */
        doAnswer(new Answer<Void>() {
            @Override
            public Void answer(InvocationOnMock invocation) throws Throwable {
                String aid = (String) invocation.getArguments()[0];
                Message message = (Message) invocation.getArguments()[2];
                AsyncResult ar = new AsyncResult(null, null, null);
                if (aid.equals(ARAM)) {
                    message.arg2 = 1;
                } else if (aid.equals(ARAD)) {
                    message.arg2 = 0;
                } else {
                    // PKCS15
                    ar = new AsyncResult(null, new int[]{2}, null);
                }
                message.obj = ar;
                message.sendToTarget();
                return null;
            }
        }).when(mUiccProfile).iccOpenLogicalChannel(anyString(), anyInt(), any(Message.class));

        // Select files
        doAnswer(new Answer<Void>() {
            @Override
            public Void answer(InvocationOnMock invocation) throws Throwable {
                Message message = (Message) invocation.getArguments()[7];
                AsyncResult ar = new AsyncResult(null, new int[]{2}, null);
                message.obj = ar;
                message.sendToTarget();
                return null;
            }
        }).when(mUiccProfile).iccTransmitApduLogicalChannel(anyInt(), eq(0x00), eq(0xA4), eq(0x00),
                eq(0x04), eq(0x02), anyString(), any(Message.class));

        // Read binary - ODF
        String odf = "A706300404025207";
        doAnswer(new Answer<Void>() {
            @Override
            public Void answer(InvocationOnMock invocation) throws Throwable {
                Message message = (Message) invocation.getArguments()[7];
                IccIoResult iir = new IccIoResult(0x90, 0x00, IccUtils.hexStringToBytes(odf));
                AsyncResult ar = new AsyncResult(null, iir, null);
                message.obj = ar;
                message.sendToTarget();
                return null;
            }
        }).when(mUiccProfile).iccTransmitApduLogicalChannel(anyInt(), eq(0x00), eq(0xB0), eq(0x00),
                eq(0x00), eq(0x00), eq("5031"), any(Message.class));

        // Read binary - DODF
        String dodf =
                "A1293000300F0C0D4750205345204163632043746CA11"
                        + "43012060A2A864886FC6B81480101300404024200";
        doAnswer(new Answer<Void>() {
            @Override
            public Void answer(InvocationOnMock invocation) throws Throwable {
                Message message = (Message) invocation.getArguments()[7];
                IccIoResult iir = new IccIoResult(0x90, 0x00, IccUtils.hexStringToBytes(dodf));
                AsyncResult ar = new AsyncResult(null, iir, null);
                message.obj = ar;
                message.sendToTarget();
                return null;
            }
        }).when(mUiccProfile).iccTransmitApduLogicalChannel(anyInt(), eq(0x00), eq(0xB0), eq(0x00),
                eq(0x00), eq(0x00), eq("5207"), any(Message.class));

        // Read binary - ACMF
        String acmf = "301004080102030405060708300404024300";
        doAnswer(new Answer<Void>() {
            @Override
            public Void answer(InvocationOnMock invocation) throws Throwable {
                Message message = (Message) invocation.getArguments()[7];
                IccIoResult iir = new IccIoResult(0x90, 0x00, IccUtils.hexStringToBytes(acmf));
                AsyncResult ar = new AsyncResult(null, iir, null);
                message.obj = ar;
                message.sendToTarget();
                return null;
            }
        }).when(mUiccProfile).iccTransmitApduLogicalChannel(anyInt(), eq(0x00), eq(0xB0), eq(0x00),
                eq(0x00), eq(0x00), eq("4200"), any(Message.class));

        // Read binary - ACRF
        String acrf = "3010A0080406FFFFFFFFFFFF300404024310";
        doAnswer(new Answer<Void>() {
            @Override
            public Void answer(InvocationOnMock invocation) throws Throwable {
                Message message = (Message) invocation.getArguments()[7];
                IccIoResult iir = new IccIoResult(0x90, 0x00, IccUtils.hexStringToBytes(acrf));
                AsyncResult ar = new AsyncResult(null, iir, null);
                message.obj = ar;
                message.sendToTarget();
                return null;
            }
        }).when(mUiccProfile).iccTransmitApduLogicalChannel(anyInt(), eq(0x00), eq(0xB0), eq(0x00),
                eq(0x00), eq(0x00), eq("4300"), any(Message.class));

        // Read binary - ACCF
        String accf =
                "30220420B9CFCE1C47A6AC713442718F15EF55B00B3A6D1A6D48CB46249FA8EB514653503022042"
                        + "04C36AF4A5BDAD97C1F3D8B283416D244496C2AC5EAFE8226079EF6F676FD1859";
        doAnswer(new Answer<Void>() {
            @Override
            public Void answer(InvocationOnMock invocation) throws Throwable {
                Message message = (Message) invocation.getArguments()[7];
                IccIoResult iir = new IccIoResult(0x90, 0x00, IccUtils.hexStringToBytes(accf));
                AsyncResult ar = new AsyncResult(null, iir, null);
                message.obj = ar;
                message.sendToTarget();
                return null;
            }
        }).when(mUiccProfile).iccTransmitApduLogicalChannel(anyInt(), eq(0x00), eq(0xB0), eq(0x00),
                eq(0x00), eq(0x00), eq("4310"), any(Message.class));


        doAnswer(new Answer<Void>() {
            @Override
            public Void answer(InvocationOnMock invocation) throws Throwable {
                Message message = (Message) invocation.getArguments()[1];
                message.sendToTarget();
                return null;
            }
        }).when(mUiccProfile).iccCloseLogicalChannel(anyInt(), any(Message.class));

        mUiccCarrierPrivilegeRules = new UiccCarrierPrivilegeRules(mUiccProfile, null);
        processAllMessages();

        assertTrue(mUiccCarrierPrivilegeRules.hasCarrierPrivilegeRules());
        assertEquals(2, mUiccCarrierPrivilegeRules.getAccessRules().size());
        List<UiccAccessRule> accessRules = mUiccCarrierPrivilegeRules.getAccessRules();
        UiccAccessRule accessRule1 = new UiccAccessRule(
                IccUtils.hexStringToBytes(
                        "B9CFCE1C47A6AC713442718F15EF55B00B3A6D1A6D48CB46249FA8EB51465350"),
                "",
                0x00);
        assertTrue(accessRules.contains(accessRule1));
        UiccAccessRule accessRule2 = new UiccAccessRule(
                IccUtils.hexStringToBytes(
                        "4C36AF4A5BDAD97C1F3D8B283416D244496C2AC5EAFE8226079EF6F676FD1859"),
                "",
                0x00);
        assertTrue(accessRules.contains(accessRule2));
    }

    @Test
    @SmallTest
    public void testAID_ARFFallbackToACRF() {
        doAnswer(new Answer<Void>() {
            @Override
            public Void answer(InvocationOnMock invocation) throws Throwable {
                String aid = (String) invocation.getArguments()[0];
                Message message = (Message) invocation.getArguments()[2];
                AsyncResult ar = new AsyncResult(null, null, null);
                if (aid.equals(ARAM)) {
                    message.arg2 = 1;
                } else if (aid.equals(ARAD)) {
                    message.arg2 = 0;
                } else {
                    // PKCS15
                    ar = new AsyncResult(null, new int[]{2}, null);
                }
                message.obj = ar;
                message.sendToTarget();
                return null;
            }
        }).when(mUiccProfile).iccOpenLogicalChannel(anyString(), anyInt(), any(Message.class));

        // Select files
        doAnswer(new Answer<Void>() {
            @Override
            public Void answer(InvocationOnMock invocation) throws Throwable {
                Message message = (Message) invocation.getArguments()[7];
                AsyncResult ar = new AsyncResult(null, new int[]{2}, null);
                message.obj = ar;
                message.sendToTarget();
                return null;
            }
        }).when(mUiccProfile).iccTransmitApduLogicalChannel(anyInt(), eq(0x00), eq(0xA4), eq(0x00),
                eq(0x04), eq(0x02), anyString(), any(Message.class));

        // Read binary ODF failed
        doAnswer(new Answer<Void>() {
            @Override
            public Void answer(InvocationOnMock invocation) throws Throwable {
                Message message = (Message) invocation.getArguments()[7];
                IccIoResult iir = new IccIoResult(0x90, 0x00, new byte[]{});
                AsyncResult ar = new AsyncResult(null, iir, null);
                message.obj = ar;
                message.sendToTarget();
                return null;
            }
        }).when(mUiccProfile).iccTransmitApduLogicalChannel(anyInt(), eq(0x00), eq(0xB0), eq(0x00),
                eq(0x00), eq(0x00), eq("5031"), any(Message.class));

        // Read binary - ACRF
        String acrf = "3010A0080406FFFFFFFFFFFF300404024310";
        doAnswer(new Answer<Void>() {
            @Override
            public Void answer(InvocationOnMock invocation) throws Throwable {
                Message message = (Message) invocation.getArguments()[7];
                IccIoResult iir = new IccIoResult(0x90, 0x00, IccUtils.hexStringToBytes(acrf));
                AsyncResult ar = new AsyncResult(null, iir, null);
                message.obj = ar;
                message.sendToTarget();
                return null;
            }
        }).when(mUiccProfile).iccTransmitApduLogicalChannel(anyInt(), eq(0x00), eq(0xB0), eq(0x00),
                eq(0x00), eq(0x00), eq("4300"), any(Message.class));

        // Read binary - ACCF
        String accf =
                "30220420B9CFCE1C47A6AC713442718F15EF55B00B3A6D1A6D48CB46249FA8EB514653503022042"
                        + "04C36AF4A5BDAD97C1F3D8B283416D244496C2AC5EAFE8226079EF6F676FD1859";
        doAnswer(new Answer<Void>() {
            @Override
            public Void answer(InvocationOnMock invocation) throws Throwable {
                Message message = (Message) invocation.getArguments()[7];
                IccIoResult iir = new IccIoResult(0x90, 0x00, IccUtils.hexStringToBytes(accf));
                AsyncResult ar = new AsyncResult(null, iir, null);
                message.obj = ar;
                message.sendToTarget();
                return null;
            }
        }).when(mUiccProfile).iccTransmitApduLogicalChannel(anyInt(), eq(0x00), eq(0xB0), eq(0x00),
                eq(0x00), eq(0x00), eq("4310"), any(Message.class));


        doAnswer(new Answer<Void>() {
            @Override
            public Void answer(InvocationOnMock invocation) throws Throwable {
                Message message = (Message) invocation.getArguments()[1];
                message.sendToTarget();
                return null;
            }
        }).when(mUiccProfile).iccCloseLogicalChannel(anyInt(), any(Message.class));

        mUiccCarrierPrivilegeRules = new UiccCarrierPrivilegeRules(mUiccProfile, null);
        processAllMessages();

        assertTrue(mUiccCarrierPrivilegeRules.hasCarrierPrivilegeRules());
        assertEquals(2, mUiccCarrierPrivilegeRules.getAccessRules().size());
        List<UiccAccessRule> accessRules = mUiccCarrierPrivilegeRules.getAccessRules();
        UiccAccessRule accessRule1 = new UiccAccessRule(
                IccUtils.hexStringToBytes(
                        "B9CFCE1C47A6AC713442718F15EF55B00B3A6D1A6D48CB46249FA8EB51465350"),
                "",
                0x00);
        assertTrue(accessRules.contains(accessRule1));
        UiccAccessRule accessRule2 = new UiccAccessRule(
                IccUtils.hexStringToBytes(
                        "4C36AF4A5BDAD97C1F3D8B283416D244496C2AC5EAFE8226079EF6F676FD1859"),
                "",
                0x00);
        assertTrue(accessRules.contains(accessRule2));
    }

    private static final int P2 = 0x40;
    private static final int P2_EXTENDED_DATA = 0x60;

    @Test
    @SmallTest
    public void testAID_RetransmitLogicalChannel() {