UiccCarrierPrivilegeRules.java revision 8071f9cde13df71af0c4c8b3810d24740279da9a
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 17package com.android.internal.telephony.uicc; 18 19import android.content.Intent; 20import android.content.pm.PackageInfo; 21import android.content.pm.PackageManager; 22import android.content.pm.ResolveInfo; 23import android.content.pm.Signature; 24import android.os.AsyncResult; 25import android.os.Binder; 26import android.os.Handler; 27import android.os.Message; 28import android.telephony.Rlog; 29import android.telephony.TelephonyManager; 30 31import com.android.internal.telephony.CommandsInterface; 32import com.android.internal.telephony.uicc.IccUtils; 33 34import java.io.ByteArrayInputStream; 35import java.lang.IllegalArgumentException; 36import java.security.MessageDigest; 37import java.security.NoSuchAlgorithmException; 38import java.security.cert.Certificate; 39import java.security.cert.CertificateException; 40import java.security.cert.CertificateFactory; 41import java.security.cert.X509Certificate; 42import java.util.ArrayList; 43import java.util.Arrays; 44import java.util.List; 45import java.util.Locale; 46import 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 */ 65public 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 181 public UiccCarrierPrivilegeRules(UiccCard uiccCard) { 182 Rlog.d(LOG_TAG, "Creating UiccCarrierPrivilegeRules"); 183 mUiccCard = uiccCard; 184 mState = new AtomicInteger(STATE_LOADING); 185 186 // Start loading the rules. 187 mUiccCard.iccOpenLogicalChannel(AID, 188 obtainMessage(EVENT_OPEN_LOGICAL_CHANNEL_DONE, null)); 189 } 190 191 /** 192 * Returns the status of the carrier privileges for the input certificate and package name. 193 * 194 * @param signature The signature of the certificate. 195 * @param packageName name of the package. 196 * @return Access status. 197 */ 198 public int getCarrierPrivilegeStatus(Signature signature, String packageName) { 199 Rlog.d(LOG_TAG, "hasCarrierPrivileges: " + signature + " : " + packageName); 200 int state = mState.get(); 201 if (state == STATE_LOADING) { 202 Rlog.d(LOG_TAG, "Rules not loaded."); 203 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED; 204 } else if (state == STATE_ERROR) { 205 Rlog.d(LOG_TAG, "Error loading rules."); 206 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES; 207 } 208 209 byte[] certHash = getCertHash(signature); 210 if (certHash == null) { 211 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS; 212 } 213 Rlog.e(LOG_TAG, "Checking: " + IccUtils.bytesToHexString(certHash) + " : " + packageName); 214 215 for (AccessRule ar : mAccessRules) { 216 if (ar.matches(certHash, packageName)) { 217 Rlog.d(LOG_TAG, "Match found!"); 218 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; 219 } 220 } 221 222 Rlog.d(LOG_TAG, "No matching rule found. Returning false."); 223 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS; 224 } 225 226 /** 227 * Returns the status of the carrier privileges for the input package name. 228 * 229 * @param packageManager PackageManager for getting signatures. 230 * @param packageName name of the package. 231 * @return Access status. 232 */ 233 public int getCarrierPrivilegeStatus(PackageManager packageManager, String packageName) { 234 try { 235 PackageInfo pInfo = packageManager.getPackageInfo(packageName, 236 PackageManager.GET_SIGNATURES); 237 Signature[] signatures = pInfo.signatures; 238 for (Signature sig : signatures) { 239 int accessStatus = getCarrierPrivilegeStatus(sig, pInfo.packageName); 240 if (accessStatus != TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS) { 241 return accessStatus; 242 } 243 } 244 } catch (PackageManager.NameNotFoundException ex) { 245 Rlog.e(LOG_TAG, "NameNotFoundException", ex); 246 } 247 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS; 248 } 249 250 /** 251 * Returns the status of the carrier privileges for the caller of the current transaction. 252 * 253 * @param packageManager PackageManager for getting signatures and package names. 254 * @return Access status. 255 */ 256 public int getCarrierPrivilegeStatusForCurrentTransaction(PackageManager packageManager) { 257 String[] packages = packageManager.getPackagesForUid(Binder.getCallingUid()); 258 259 for (String pkg : packages) { 260 int accessStatus = getCarrierPrivilegeStatus(packageManager, pkg); 261 if (accessStatus != TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS) { 262 return accessStatus; 263 } 264 } 265 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS; 266 } 267 268 /** 269 * Returns the package name of the carrier app that should handle the input intent. 270 * 271 * @param packageManager PackageManager for getting receivers. 272 * @param intent Intent that will be broadcast. 273 * @return list of carrier app package names that can handle the intent. 274 * Returns null if there is an error and an empty list if there 275 * are no matching packages. 276 */ 277 public List<String> getCarrierPackageNamesForBroadcastIntent( 278 PackageManager packageManager, Intent intent) { 279 List<String> packages = new ArrayList<String>(); 280 List<ResolveInfo> receivers = packageManager.queryBroadcastReceivers(intent, 0); 281 for (ResolveInfo resolveInfo : receivers) { 282 if (resolveInfo.activityInfo == null) { 283 continue; 284 } 285 String packageName = resolveInfo.activityInfo.packageName; 286 int status = getCarrierPrivilegeStatus(packageManager, packageName); 287 if (status == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { 288 packages.add(packageName); 289 } else if (status != TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS) { 290 // Any status apart from HAS_ACCESS and NO_ACCESS is considered an error. 291 return null; 292 } 293 } 294 295 return packages; 296 } 297 298 @Override 299 public void handleMessage(Message msg) { 300 AsyncResult ar; 301 302 switch (msg.what) { 303 304 case EVENT_OPEN_LOGICAL_CHANNEL_DONE: 305 Rlog.d(LOG_TAG, "EVENT_OPEN_LOGICAL_CHANNEL_DONE"); 306 ar = (AsyncResult) msg.obj; 307 if (ar.exception == null && ar.result != null) { 308 int channelId = ((int[]) ar.result)[0]; 309 mUiccCard.iccTransmitApduLogicalChannel(channelId, CLA, COMMAND, P1, P2, P3, DATA, 310 obtainMessage(EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE, new Integer(channelId))); 311 } else { 312 Rlog.e(LOG_TAG, "Error opening channel"); 313 mState.set(STATE_ERROR); 314 } 315 break; 316 317 case EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE: 318 Rlog.d(LOG_TAG, "EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE"); 319 ar = (AsyncResult) msg.obj; 320 if (ar.exception == null && ar.result != null) { 321 IccIoResult response = (IccIoResult) ar.result; 322 if (response.payload != null && response.sw1 == 0x90 && response.sw2 == 0x00) { 323 try { 324 mAccessRules = parseRules(IccUtils.bytesToHexString(response.payload)); 325 mState.set(STATE_LOADED); 326 } catch (IllegalArgumentException ex) { 327 Rlog.e(LOG_TAG, "Error parsing rules: " + ex); 328 mState.set(STATE_ERROR); 329 } 330 } else { 331 Rlog.e(LOG_TAG, "Invalid response: payload=" + response.payload + 332 " sw1=" + response.sw1 + " sw2=" + response.sw2); 333 } 334 } else { 335 Rlog.e(LOG_TAG, "Error reading value from SIM."); 336 mState.set(STATE_ERROR); 337 } 338 339 int channelId = (Integer) ar.userObj; 340 mUiccCard.iccCloseLogicalChannel(channelId, obtainMessage( 341 EVENT_CLOSE_LOGICAL_CHANNEL_DONE)); 342 break; 343 344 case EVENT_CLOSE_LOGICAL_CHANNEL_DONE: 345 Rlog.d(LOG_TAG, "EVENT_CLOSE_LOGICAL_CHANNEL_DONE"); 346 break; 347 348 default: 349 Rlog.e(LOG_TAG, "Unknown event " + msg.what); 350 } 351 } 352 353 /* 354 * Parses the rules from the input string. 355 */ 356 private static List<AccessRule> parseRules(String rules) { 357 rules = rules.toUpperCase(Locale.US); 358 Rlog.d(LOG_TAG, "Got rules: " + rules); 359 360 TLV allRefArDo = new TLV(TAG_ALL_REF_AR_DO); //FF40 361 allRefArDo.parse(rules, true); 362 363 String arDos = allRefArDo.value; 364 List<AccessRule> accessRules = new ArrayList<AccessRule>(); 365 while (!arDos.isEmpty()) { 366 TLV refArDo = new TLV(TAG_REF_AR_DO); //E2 367 arDos = refArDo.parse(arDos, false); 368 AccessRule accessRule = parseRefArdo(refArDo.value); 369 if (accessRule != null) { 370 accessRules.add(accessRule); 371 } else { 372 Rlog.e(LOG_TAG, "Skip unrecognized rule." + refArDo.value); 373 } 374 } 375 return accessRules; 376 } 377 378 /* 379 * Parses a single rule. 380 */ 381 private static AccessRule parseRefArdo(String rule) { 382 Rlog.d(LOG_TAG, "Got rule: " + rule); 383 384 String certificateHash = null; 385 String packageName = null; 386 String tmp = null; 387 long accessType = 0; 388 389 while (!rule.isEmpty()) { 390 if (rule.startsWith(TAG_REF_DO)) { 391 TLV refDo = new TLV(TAG_REF_DO); //E1 392 rule = refDo.parse(rule, false); 393 394 // Skip unrelated rules. 395 if (!refDo.value.startsWith(TAG_DEVICE_APP_ID_REF_DO)) { 396 return null; 397 } 398 399 TLV deviceDo = new TLV(TAG_DEVICE_APP_ID_REF_DO); //C1 400 tmp = deviceDo.parse(refDo.value, false); 401 certificateHash = deviceDo.value; 402 403 if (!tmp.isEmpty()) { 404 if (!tmp.startsWith(TAG_PKG_REF_DO)) { 405 return null; 406 } 407 TLV pkgDo = new TLV(TAG_PKG_REF_DO); //CA 408 pkgDo.parse(tmp, true); 409 packageName = new String(IccUtils.hexStringToBytes(pkgDo.value)); 410 } else { 411 packageName = null; 412 } 413 } else if (rule.startsWith(TAG_AR_DO)) { 414 TLV arDo = new TLV(TAG_AR_DO); //E3 415 rule = arDo.parse(rule, false); 416 417 // Skip unrelated rules. 418 if (!arDo.value.startsWith(TAG_PERM_AR_DO)) { 419 return null; 420 } 421 422 TLV permDo = new TLV(TAG_PERM_AR_DO); //DB 423 permDo.parse(arDo.value, true); 424 Rlog.e(LOG_TAG, permDo.value); 425 } else { 426 // Spec requires it must be either TAG_REF_DO or TAG_AR_DO. 427 throw new RuntimeException("Invalid Rule type"); 428 } 429 } 430 431 Rlog.e(LOG_TAG, "Adding: " + certificateHash + " : " + packageName + " : " + accessType); 432 433 AccessRule accessRule = new AccessRule(IccUtils.hexStringToBytes(certificateHash), 434 packageName, accessType); 435 Rlog.e(LOG_TAG, "Parsed rule: " + accessRule); 436 return accessRule; 437 } 438 439 /* 440 * Converts a Signature into a Certificate hash usable for comparison. 441 */ 442 private static byte[] getCertHash(Signature signature) { 443 // TODO: Is the following sufficient. 444 try { 445 CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); 446 X509Certificate cert = (X509Certificate) certFactory.generateCertificate( 447 new ByteArrayInputStream(signature.toByteArray())); 448 449 MessageDigest md = MessageDigest.getInstance("SHA"); 450 return md.digest(cert.getEncoded()); 451 } catch (CertificateException ex) { 452 Rlog.e(LOG_TAG, "CertificateException: " + ex); 453 } catch (NoSuchAlgorithmException ex) { 454 Rlog.e(LOG_TAG, "NoSuchAlgorithmException: " + ex); 455 } 456 457 Rlog.e(LOG_TAG, "Cannot compute cert hash"); 458 return null; 459 } 460} 461