Loading src/java/com/android/internal/telephony/uicc/UiccPkcs15.java +163 −8 Original line number Diff line number Diff line Loading @@ -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" Loading Loading @@ -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"); } Loading Loading @@ -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); Loading @@ -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>(); Loading Loading @@ -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) { Loading @@ -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 Loading @@ -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 Loading tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRulesTest.java +285 −5 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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() { Loading Loading @@ -476,7 +479,7 @@ public class UiccCarrierPrivilegeRulesTest extends TelephonyTest { @Test @SmallTest public void testAID_NeitherARAMorARAD() { public void testAID_ARFFailed() { final String hexString = "FF4045E243E135C114ABCD92CBB156B280FA4E1429A6ECEEB6E5C1BFE4CA1D636F6D2E676F6F676" + "C652E616E64726F69642E617070732E6D79617070E30ADB080000000000000001"; Loading Loading @@ -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() { Loading Loading
src/java/com/android/internal/telephony/uicc/UiccPkcs15.java +163 −8 Original line number Diff line number Diff line Loading @@ -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" Loading Loading @@ -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"); } Loading Loading @@ -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); Loading @@ -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>(); Loading Loading @@ -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) { Loading @@ -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 Loading @@ -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 Loading
tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRulesTest.java +285 −5 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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() { Loading Loading @@ -476,7 +479,7 @@ public class UiccCarrierPrivilegeRulesTest extends TelephonyTest { @Test @SmallTest public void testAID_NeitherARAMorARAD() { public void testAID_ARFFailed() { final String hexString = "FF4045E243E135C114ABCD92CBB156B280FA4E1429A6ECEEB6E5C1BFE4CA1D636F6D2E676F6F676" + "C652E616E64726F69642E617070732E6D79617070E30ADB080000000000000001"; Loading Loading @@ -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() { Loading