1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.compatibility.common.util; 18 19 import android.Manifest; 20 import android.telephony.TelephonyManager; 21 22 import androidx.annotation.Nullable; 23 import androidx.annotation.StringDef; 24 import androidx.test.InstrumentationRegistry; 25 26 import java.util.List; 27 28 /** Utility class for common UICC- and SIM-related operations. */ 29 public final class UiccUtil { 30 31 // A table mapping from a number to a hex character for fast encoding hex strings. 32 private static final char[] HEX_CHARS = { 33 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' 34 }; 35 36 /** 37 * Data class representing a single APDU transmission. 38 * 39 * <p>Constants are defined in TS 102 221 Section 10.1.2. 40 */ 41 public static final class ApduCommand { 42 public static final int INS_GET_RESPONSE = 0xC0; 43 44 public final int cla; 45 public final int ins; 46 public final int p1; 47 public final int p2; 48 public final int p3; 49 @Nullable public final String data; 50 ApduCommand(int cla, int ins, int p1, int p2, int p3, @Nullable String data)51 public ApduCommand(int cla, int ins, int p1, int p2, int p3, @Nullable String data) { 52 this.cla = cla; 53 this.ins = ins; 54 this.p1 = p1; 55 this.p2 = p2; 56 this.p3 = p3; 57 this.data = data; 58 } 59 60 @Override toString()61 public String toString() { 62 return "cla=0x" 63 + Integer.toHexString(cla) 64 + ", ins=0x" 65 + Integer.toHexString(ins) 66 + ", p1=0x" 67 + Integer.toHexString(p1) 68 + ", p2=0x" 69 + Integer.toHexString(p2) 70 + ", p3=0x" 71 + Integer.toHexString(p3) 72 + ", data=" 73 + data; 74 } 75 } 76 77 /** Various APDU status words and their meanings, as defined in TS 102 221 Section 10.2.1 */ 78 public static final class ApduResponse { 79 public static final String SW1_MORE_RESPONSE = "61"; 80 81 public static final String SW1_SW2_OK = "9000"; 82 public static final String SW1_OK_PROACTIVE_COMMAND = "91"; 83 } 84 85 /** 86 * The hashes of all supported CTS UICC test keys and their corresponding specification. 87 * 88 * <p>For up-to-date information about the CTS SIM specification, please see 89 * https://source.android.com/devices/tech/config/uicc#validation. 90 */ 91 @StringDef({UiccCertificate.CTS_UICC_LEGACY, UiccCertificate.CTS_UICC_2021}) 92 public @interface UiccCertificate { 93 94 /** 95 * Indicates compliance with the "legacy" CTS UICC specification (prior to 2021). 96 * 97 * <p>Corresponding certificate: {@code aosp-testkey}. 98 * 99 * @deprecated as of 2021, and no longer supported as of 2022. 100 */ 101 @Deprecated String CTS_UICC_LEGACY = "61ED377E85D386A8DFEE6B864BD85B0BFAA5AF81"; 102 103 /** 104 * Indicates compliance with the 2021 CTS UICC specification. 105 * 106 * <p>Strongly recommended as of 2021, required as of 2022. 107 * 108 * <p>Corresponding certificate: {@code cts-uicc-2021-testkey}. 109 */ 110 String CTS_UICC_2021 = "CE7B2B47AE2B7552C8F92CC29124279883041FB623A5F194A82C9BF15D492AA0"; 111 } 112 113 /** 114 * A simple check for use with {@link org.junit.Assume#assumeTrue}. Checks the carrier privilege 115 * certificates stored on the SIM and returns {@code true} if {@code requiredCert} is present. 116 * 117 * <p>Can be used either in the {@code #setUp} method if an entire class requires a particular 118 * UICC, or at the top of a specific {@code @Test} method. 119 * 120 * <p>If we had JUnit 5, we could create a much cooler {@code @RequiresUiccCertificate} 121 * annotation using {@code ExtendWith} and {@code ExecutionCondition}, but that isn't available 122 * to us yet. 123 */ uiccHasCertificate(@iccCertificate String requiredCert)124 public static boolean uiccHasCertificate(@UiccCertificate String requiredCert) { 125 TelephonyManager tm = 126 InstrumentationRegistry.getInstrumentation() 127 .getTargetContext() 128 .getSystemService(TelephonyManager.class); 129 List<String> uiccCerts = 130 ShellIdentityUtils.invokeMethodWithShellPermissions( 131 tm, 132 TelephonyManager::getCertsFromCarrierPrivilegeAccessRules, 133 Manifest.permission.READ_PRIVILEGED_PHONE_STATE); 134 return uiccCerts == null ? false : uiccCerts.contains(requiredCert); 135 } 136 137 /** 138 * Converts a byte array into a String of hexadecimal characters. 139 * 140 * @param bytes an array of bytes 141 * @return hex string representation of bytes array 142 */ 143 @Nullable bytesToHexString(@ullable byte[] bytes)144 public static String bytesToHexString(@Nullable byte[] bytes) { 145 if (bytes == null) return null; 146 147 StringBuilder ret = new StringBuilder(2 * bytes.length); 148 149 for (int i = 0; i < bytes.length; i++) { 150 int b; 151 b = 0x0f & (bytes[i] >> 4); 152 ret.append(HEX_CHARS[b]); 153 b = 0x0f & bytes[i]; 154 ret.append(HEX_CHARS[b]); 155 } 156 157 return ret.toString(); 158 } 159 } 160