1 /* 2 * Copyright (C) 2014 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.internal.telephony.uicc; 18 19 import android.content.Intent; 20 import android.content.pm.PackageInfo; 21 import android.content.pm.PackageManager; 22 import android.content.pm.ResolveInfo; 23 import android.content.pm.Signature; 24 import android.os.AsyncResult; 25 import android.os.Binder; 26 import android.os.Handler; 27 import android.os.Message; 28 import android.telephony.Rlog; 29 import android.telephony.TelephonyManager; 30 31 import com.android.internal.telephony.CommandsInterface; 32 import com.android.internal.telephony.uicc.IccUtils; 33 34 import java.io.ByteArrayInputStream; 35 import java.lang.IllegalArgumentException; 36 import java.security.MessageDigest; 37 import java.security.NoSuchAlgorithmException; 38 import java.security.cert.Certificate; 39 import java.security.cert.CertificateException; 40 import java.security.cert.CertificateFactory; 41 import java.security.cert.X509Certificate; 42 import java.util.ArrayList; 43 import java.util.Arrays; 44 import java.util.List; 45 import java.util.Locale; 46 import java.util.concurrent.atomic.AtomicInteger; 47 48 /** 49 * Class that reads and stores the carrier privileged rules from the UICC. 50 * 51 * The rules are read when the class is created, hence it should only be created 52 * after the UICC can be read. And it should be deleted when a UICC is changed. 53 * 54 * The spec for the rules: 55 * GP Secure Element Access Control: 56 * http://www.globalplatform.org/specifications/review/GPD_SE_Access_Control_v1.0.20.pdf 57 * Extension spec: 58 * https://code.google.com/p/seek-for-android/ 59 * 60 * 61 * TODO: Notifications. 62 * 63 * {@hide} 64 */ 65 public class UiccCarrierPrivilegeRules extends Handler { 66 private static final String LOG_TAG = "UiccCarrierPrivilegeRules"; 67 68 private static final String AID = "A00000015141434C00"; 69 private static final int CLA = 0x80; 70 private static final int COMMAND = 0xCA; 71 private static final int P1 = 0xFF; 72 private static final int P2 = 0x40; 73 private static final int P3 = 0x00; 74 private static final String DATA = ""; 75 76 /* 77 * Rules format: 78 * ALL_REF_AR_DO = TAG_ALL_REF_AR_DO + len + [REF_AR_DO]*n 79 * REF_AR_DO = TAG_REF_AR_DO + len + REF-DO + AR-DO 80 * 81 * REF_DO = TAG_REF_DO + len + DEVICE_APP_ID_REF_DO + (optional) PKG_REF_DO 82 * AR_DO = TAG_AR_DO + len + PERM_AR_DO 83 * 84 * DEVICE_APP_ID_REF_DO = TAG_DEVICE_APP_ID_REF_DO + len + sha1 hexstring of cert (20 bytes) 85 * PKG_REF_DO = TAG_PKG_REF_DO + len + package name 86 * PERM_AR_DO = TAG_PERM_AR_DO + len + detailed permission (8 bytes) 87 * 88 * Data objects hierarchy by TAG: 89 * FF40 90 * E2 91 * E1 92 * C1 93 * CA 94 * E3 95 * DB 96 */ 97 // Values from the data standard. 98 private static final String TAG_ALL_REF_AR_DO = "FF40"; 99 private static final String TAG_REF_AR_DO = "E2"; 100 private static final String TAG_REF_DO = "E1"; 101 private static final String TAG_DEVICE_APP_ID_REF_DO = "C1"; 102 private static final String TAG_PKG_REF_DO = "CA"; 103 private static final String TAG_AR_DO = "E3"; 104 private static final String TAG_PERM_AR_DO = "DB"; 105 106 private static final int EVENT_OPEN_LOGICAL_CHANNEL_DONE = 1; 107 private static final int EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE = 2; 108 private static final int EVENT_CLOSE_LOGICAL_CHANNEL_DONE = 3; 109 110 // State of the object. 111 private static final int STATE_LOADING = 0; 112 private static final int STATE_LOADED = 1; 113 private static final int STATE_ERROR = 2; 114 115 // Describes a single rule. 116 private static class AccessRule { 117 public byte[] certificateHash; 118 public String packageName; 119 public long accessType; // This bit is not currently used, but reserved for future use. 120 121 AccessRule(byte[] certificateHash, String packageName, long accessType) { 122 this.certificateHash = certificateHash; 123 this.packageName = packageName; 124 this.accessType = accessType; 125 } 126 127 boolean matches(byte[] certHash, String packageName) { 128 return certHash != null && Arrays.equals(this.certificateHash, certHash) && 129 (this.packageName == null || this.packageName.equals(packageName)); 130 } 131 132 @Override 133 public String toString() { 134 return "cert: " + certificateHash + " pkg: " + packageName + 135 " access: " + accessType; 136 } 137 } 138 139 // Used for parsing the data from the UICC. 140 private static class TLV { 141 private String tag; 142 private Integer length; 143 private String value; 144 145 public TLV(String tag) { 146 this.tag = tag; 147 } 148 149 public String parse(String data, boolean shouldConsumeAll) { 150 Rlog.d(LOG_TAG, "Parse TLV: " + tag); 151 if (!data.startsWith(tag)) { 152 throw new IllegalArgumentException("Tags don't match."); 153 } 154 int index = tag.length(); 155 if (index + 2 > data.length()) { 156 throw new IllegalArgumentException("No length."); 157 } 158 length = new Integer(2 * Integer.parseInt( 159 data.substring(index, index + 2), 16)); 160 index += 2; 161 162 int remainingLength = data.length() - (index + length); 163 if (remainingLength < 0) { 164 throw new IllegalArgumentException("Not enough data."); 165 } 166 if (shouldConsumeAll && (remainingLength != 0)) { 167 throw new IllegalArgumentException("Did not consume all."); 168 } 169 value = data.substring(index, index + length); 170 171 Rlog.d(LOG_TAG, "Got TLV: " + tag + "," + length + "," + value); 172 173 return data.substring(index + length); 174 } 175 } 176 177 private UiccCard mUiccCard; // Parent 178 private AtomicInteger mState; 179 private List<AccessRule> mAccessRules; 180 private Message mLoadedCallback; 181 182 public UiccCarrierPrivilegeRules(UiccCard uiccCard, Message loadedCallback) { 183 Rlog.d(LOG_TAG, "Creating UiccCarrierPrivilegeRules"); 184 mUiccCard = uiccCard; 185 mState = new AtomicInteger(STATE_LOADING); 186 mLoadedCallback = loadedCallback; 187 188 // Start loading the rules. 189 mUiccCard.iccOpenLogicalChannel(AID, 190 obtainMessage(EVENT_OPEN_LOGICAL_CHANNEL_DONE, null)); 191 } 192 193 /** 194 * Returns true if the carrier privilege rules have finished loading. 195 */ 196 public boolean areCarrierPriviligeRulesLoaded() { 197 return mState.get() != STATE_LOADING; 198 } 199 200 /** 201 * Returns the status of the carrier privileges for the input certificate and package name. 202 * 203 * @param signature The signature of the certificate. 204 * @param packageName name of the package. 205 * @return Access status. 206 */ 207 public int getCarrierPrivilegeStatus(Signature signature, String packageName) { 208 Rlog.d(LOG_TAG, "hasCarrierPrivileges: " + signature + " : " + packageName); 209 int state = mState.get(); 210 if (state == STATE_LOADING) { 211 Rlog.d(LOG_TAG, "Rules not loaded."); 212 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED; 213 } else if (state == STATE_ERROR) { 214 Rlog.d(LOG_TAG, "Error loading rules."); 215 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES; 216 } 217 218 byte[] certHash = getCertHash(signature); 219 if (certHash == null) { 220 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS; 221 } 222 Rlog.e(LOG_TAG, "Checking: " + IccUtils.bytesToHexString(certHash) + " : " + packageName); 223 224 for (AccessRule ar : mAccessRules) { 225 if (ar.matches(certHash, packageName)) { 226 Rlog.d(LOG_TAG, "Match found!"); 227 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; 228 } 229 } 230 231 Rlog.d(LOG_TAG, "No matching rule found. Returning false."); 232 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS; 233 } 234 235 /** 236 * Returns the status of the carrier privileges for the input package name. 237 * 238 * @param packageManager PackageManager for getting signatures. 239 * @param packageName name of the package. 240 * @return Access status. 241 */ 242 public int getCarrierPrivilegeStatus(PackageManager packageManager, String packageName) { 243 try { 244 PackageInfo pInfo = packageManager.getPackageInfo(packageName, 245 PackageManager.GET_SIGNATURES); 246 Signature[] signatures = pInfo.signatures; 247 for (Signature sig : signatures) { 248 int accessStatus = getCarrierPrivilegeStatus(sig, pInfo.packageName); 249 if (accessStatus != TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS) { 250 return accessStatus; 251 } 252 } 253 } catch (PackageManager.NameNotFoundException ex) { 254 Rlog.e(LOG_TAG, "NameNotFoundException", ex); 255 } 256 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS; 257 } 258 259 /** 260 * Returns the status of the carrier privileges for the caller of the current transaction. 261 * 262 * @param packageManager PackageManager for getting signatures and package names. 263 * @return Access status. 264 */ 265 public int getCarrierPrivilegeStatusForCurrentTransaction(PackageManager packageManager) { 266 String[] packages = packageManager.getPackagesForUid(Binder.getCallingUid()); 267 268 for (String pkg : packages) { 269 int accessStatus = getCarrierPrivilegeStatus(packageManager, pkg); 270 if (accessStatus != TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS) { 271 return accessStatus; 272 } 273 } 274 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS; 275 } 276 277 /** 278 * Returns the package name of the carrier app that should handle the input intent. 279 * 280 * @param packageManager PackageManager for getting receivers. 281 * @param intent Intent that will be sent. 282 * @return list of carrier app package names that can handle the intent. 283 * Returns null if there is an error and an empty list if there 284 * are no matching packages. 285 */ 286 public List<String> getCarrierPackageNamesForIntent( 287 PackageManager packageManager, Intent intent) { 288 List<String> packages = new ArrayList<String>(); 289 List<ResolveInfo> receivers = new ArrayList<ResolveInfo>(); 290 receivers.addAll(packageManager.queryBroadcastReceivers(intent, 0)); 291 receivers.addAll(packageManager.queryIntentContentProviders(intent, 0)); 292 receivers.addAll(packageManager.queryIntentActivities(intent, 0)); 293 receivers.addAll(packageManager.queryIntentServices(intent, 0)); 294 295 for (ResolveInfo resolveInfo : receivers) { 296 if (resolveInfo.activityInfo == null) { 297 continue; 298 } 299 String packageName = resolveInfo.activityInfo.packageName; 300 int status = getCarrierPrivilegeStatus(packageManager, packageName); 301 if (status == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { 302 packages.add(packageName); 303 } else if (status != TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS) { 304 // Any status apart from HAS_ACCESS and NO_ACCESS is considered an error. 305 return null; 306 } 307 } 308 309 return packages; 310 } 311 312 @Override 313 public void handleMessage(Message msg) { 314 AsyncResult ar; 315 316 switch (msg.what) { 317 318 case EVENT_OPEN_LOGICAL_CHANNEL_DONE: 319 Rlog.d(LOG_TAG, "EVENT_OPEN_LOGICAL_CHANNEL_DONE"); 320 ar = (AsyncResult) msg.obj; 321 if (ar.exception == null && ar.result != null) { 322 int channelId = ((int[]) ar.result)[0]; 323 mUiccCard.iccTransmitApduLogicalChannel(channelId, CLA, COMMAND, P1, P2, P3, DATA, 324 obtainMessage(EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE, new Integer(channelId))); 325 } else { 326 Rlog.e(LOG_TAG, "Error opening channel"); 327 updateState(STATE_ERROR); 328 } 329 break; 330 331 case EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE: 332 Rlog.d(LOG_TAG, "EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE"); 333 ar = (AsyncResult) msg.obj; 334 if (ar.exception == null && ar.result != null) { 335 IccIoResult response = (IccIoResult) ar.result; 336 if (response.payload != null && response.sw1 == 0x90 && response.sw2 == 0x00) { 337 try { 338 mAccessRules = parseRules(IccUtils.bytesToHexString(response.payload)); 339 updateState(STATE_LOADED); 340 } catch (IllegalArgumentException ex) { 341 Rlog.e(LOG_TAG, "Error parsing rules: " + ex); 342 updateState(STATE_ERROR); 343 } 344 } else { 345 Rlog.e(LOG_TAG, "Invalid response: payload=" + response.payload + 346 " sw1=" + response.sw1 + " sw2=" + response.sw2); 347 updateState(STATE_ERROR); 348 } 349 } else { 350 Rlog.e(LOG_TAG, "Error reading value from SIM."); 351 updateState(STATE_ERROR); 352 } 353 354 int channelId = (Integer) ar.userObj; 355 mUiccCard.iccCloseLogicalChannel(channelId, obtainMessage( 356 EVENT_CLOSE_LOGICAL_CHANNEL_DONE)); 357 break; 358 359 case EVENT_CLOSE_LOGICAL_CHANNEL_DONE: 360 Rlog.d(LOG_TAG, "EVENT_CLOSE_LOGICAL_CHANNEL_DONE"); 361 break; 362 363 default: 364 Rlog.e(LOG_TAG, "Unknown event " + msg.what); 365 } 366 } 367 368 /* 369 * Parses the rules from the input string. 370 */ 371 private static List<AccessRule> parseRules(String rules) { 372 rules = rules.toUpperCase(Locale.US); 373 Rlog.d(LOG_TAG, "Got rules: " + rules); 374 375 TLV allRefArDo = new TLV(TAG_ALL_REF_AR_DO); //FF40 376 allRefArDo.parse(rules, true); 377 378 String arDos = allRefArDo.value; 379 List<AccessRule> accessRules = new ArrayList<AccessRule>(); 380 while (!arDos.isEmpty()) { 381 TLV refArDo = new TLV(TAG_REF_AR_DO); //E2 382 arDos = refArDo.parse(arDos, false); 383 AccessRule accessRule = parseRefArdo(refArDo.value); 384 if (accessRule != null) { 385 accessRules.add(accessRule); 386 } else { 387 Rlog.e(LOG_TAG, "Skip unrecognized rule." + refArDo.value); 388 } 389 } 390 return accessRules; 391 } 392 393 /* 394 * Parses a single rule. 395 */ 396 private static AccessRule parseRefArdo(String rule) { 397 Rlog.d(LOG_TAG, "Got rule: " + rule); 398 399 String certificateHash = null; 400 String packageName = null; 401 String tmp = null; 402 long accessType = 0; 403 404 while (!rule.isEmpty()) { 405 if (rule.startsWith(TAG_REF_DO)) { 406 TLV refDo = new TLV(TAG_REF_DO); //E1 407 rule = refDo.parse(rule, false); 408 409 // Skip unrelated rules. 410 if (!refDo.value.startsWith(TAG_DEVICE_APP_ID_REF_DO)) { 411 return null; 412 } 413 414 TLV deviceDo = new TLV(TAG_DEVICE_APP_ID_REF_DO); //C1 415 tmp = deviceDo.parse(refDo.value, false); 416 certificateHash = deviceDo.value; 417 418 if (!tmp.isEmpty()) { 419 if (!tmp.startsWith(TAG_PKG_REF_DO)) { 420 return null; 421 } 422 TLV pkgDo = new TLV(TAG_PKG_REF_DO); //CA 423 pkgDo.parse(tmp, true); 424 packageName = new String(IccUtils.hexStringToBytes(pkgDo.value)); 425 } else { 426 packageName = null; 427 } 428 } else if (rule.startsWith(TAG_AR_DO)) { 429 TLV arDo = new TLV(TAG_AR_DO); //E3 430 rule = arDo.parse(rule, false); 431 432 // Skip unrelated rules. 433 if (!arDo.value.startsWith(TAG_PERM_AR_DO)) { 434 return null; 435 } 436 437 TLV permDo = new TLV(TAG_PERM_AR_DO); //DB 438 permDo.parse(arDo.value, true); 439 Rlog.e(LOG_TAG, permDo.value); 440 } else { 441 // Spec requires it must be either TAG_REF_DO or TAG_AR_DO. 442 throw new RuntimeException("Invalid Rule type"); 443 } 444 } 445 446 Rlog.e(LOG_TAG, "Adding: " + certificateHash + " : " + packageName + " : " + accessType); 447 448 AccessRule accessRule = new AccessRule(IccUtils.hexStringToBytes(certificateHash), 449 packageName, accessType); 450 Rlog.e(LOG_TAG, "Parsed rule: " + accessRule); 451 return accessRule; 452 } 453 454 /* 455 * Converts a Signature into a Certificate hash usable for comparison. 456 */ 457 private static byte[] getCertHash(Signature signature) { 458 // TODO: Is the following sufficient. 459 try { 460 CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); 461 X509Certificate cert = (X509Certificate) certFactory.generateCertificate( 462 new ByteArrayInputStream(signature.toByteArray())); 463 464 MessageDigest md = MessageDigest.getInstance("SHA"); 465 return md.digest(cert.getEncoded()); 466 } catch (CertificateException ex) { 467 Rlog.e(LOG_TAG, "CertificateException: " + ex); 468 } catch (NoSuchAlgorithmException ex) { 469 Rlog.e(LOG_TAG, "NoSuchAlgorithmException: " + ex); 470 } 471 472 Rlog.e(LOG_TAG, "Cannot compute cert hash"); 473 return null; 474 } 475 476 /* 477 * Updates the state and notifies the UiccCard that the rules have finished loading. 478 */ 479 private void updateState(int newState) { 480 mState.set(newState); 481 if (mLoadedCallback != null) { 482 mLoadedCallback.sendToTarget(); 483 } 484 } 485 } 486