Home | History | Annotate | Download | only in uicc
      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.annotation.Nullable;
     20 import android.content.Intent;
     21 import android.content.pm.PackageInfo;
     22 import android.content.pm.PackageManager;
     23 import android.content.pm.ResolveInfo;
     24 import android.content.pm.Signature;
     25 import android.os.AsyncResult;
     26 import android.os.Binder;
     27 import android.os.Handler;
     28 import android.os.Message;
     29 import android.telephony.Rlog;
     30 import android.telephony.TelephonyManager;
     31 import android.text.TextUtils;
     32 
     33 import com.android.internal.telephony.CommandException;
     34 import com.android.internal.telephony.CommandsInterface;
     35 import com.android.internal.telephony.uicc.IccUtils;
     36 
     37 import java.io.ByteArrayInputStream;
     38 import java.io.FileDescriptor;
     39 import java.io.PrintWriter;
     40 import java.lang.IllegalArgumentException;
     41 import java.lang.IndexOutOfBoundsException;
     42 import java.security.MessageDigest;
     43 import java.security.NoSuchAlgorithmException;
     44 import java.security.cert.Certificate;
     45 import java.security.cert.CertificateException;
     46 import java.security.cert.CertificateFactory;
     47 import java.security.cert.X509Certificate;
     48 import java.util.ArrayList;
     49 import java.util.Arrays;
     50 import java.util.List;
     51 import java.util.Locale;
     52 import java.util.concurrent.atomic.AtomicInteger;
     53 
     54 /**
     55  * Class that reads and stores the carrier privileged rules from the UICC.
     56  *
     57  * The rules are read when the class is created, hence it should only be created
     58  * after the UICC can be read. And it should be deleted when a UICC is changed.
     59  *
     60  * Document: https://source.android.com/devices/tech/config/uicc.html
     61  *
     62  * {@hide}
     63  */
     64 public class UiccCarrierPrivilegeRules extends Handler {
     65     private static final String LOG_TAG = "UiccCarrierPrivilegeRules";
     66     private static final boolean DBG = false;
     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 P2_EXTENDED_DATA = 0x60;
     74     private static final int P3 = 0x00;
     75     private static final String DATA = "";
     76 
     77     /*
     78      * Rules format:
     79      *   ALL_REF_AR_DO = TAG_ALL_REF_AR_DO + len + [REF_AR_DO]*n
     80      *   REF_AR_DO = TAG_REF_AR_DO + len + REF-DO + AR-DO
     81      *
     82      *   REF_DO = TAG_REF_DO + len + DEVICE_APP_ID_REF_DO + (optional) PKG_REF_DO
     83      *   AR_DO = TAG_AR_DO + len + PERM_AR_DO
     84      *
     85      *   DEVICE_APP_ID_REF_DO = TAG_DEVICE_APP_ID_REF_DO + len + sha256 hexstring of cert
     86      *   PKG_REF_DO = TAG_PKG_REF_DO + len + package name
     87      *   PERM_AR_DO = TAG_PERM_AR_DO + len + detailed permission (8 bytes)
     88      *
     89      * Data objects hierarchy by TAG:
     90      * FF40
     91      *   E2
     92      *     E1
     93      *       C1
     94      *       CA
     95      *     E3
     96      *       DB
     97      */
     98     // Values from the data standard.
     99     private static final String TAG_ALL_REF_AR_DO = "FF40";
    100     private static final String TAG_REF_AR_DO = "E2";
    101     private static final String TAG_REF_DO = "E1";
    102     private static final String TAG_DEVICE_APP_ID_REF_DO = "C1";
    103     private static final String TAG_PKG_REF_DO = "CA";
    104     private static final String TAG_AR_DO = "E3";
    105     private static final String TAG_PERM_AR_DO = "DB";
    106 
    107     private static final int EVENT_OPEN_LOGICAL_CHANNEL_DONE = 1;
    108     private static final int EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE = 2;
    109     private static final int EVENT_CLOSE_LOGICAL_CHANNEL_DONE = 3;
    110     private static final int EVENT_PKCS15_READ_DONE = 4;
    111 
    112     // State of the object.
    113     private static final int STATE_LOADING  = 0;
    114     private static final int STATE_LOADED   = 1;
    115     private static final int STATE_ERROR    = 2;
    116 
    117     // Max number of retries for open logical channel, interval is 10s.
    118     private static final int MAX_RETRY = 1;
    119     private static final int RETRY_INTERVAL_MS = 10000;
    120 
    121     // Describes a single rule.
    122     private static class AccessRule {
    123         public byte[] certificateHash;
    124         public String packageName;
    125         public long accessType;   // This bit is not currently used, but reserved for future use.
    126 
    127         AccessRule(byte[] certificateHash, String packageName, long accessType) {
    128             this.certificateHash = certificateHash;
    129             this.packageName = packageName;
    130             this.accessType = accessType;
    131         }
    132 
    133         boolean matches(byte[] certHash, String packageName) {
    134           return certHash != null && Arrays.equals(this.certificateHash, certHash) &&
    135                 (TextUtils.isEmpty(this.packageName) || this.packageName.equals(packageName));
    136         }
    137 
    138         @Override
    139         public String toString() {
    140             return "cert: " + IccUtils.bytesToHexString(certificateHash) + " pkg: " +
    141                 packageName + " access: " + accessType;
    142         }
    143     }
    144 
    145     // Used for parsing the data from the UICC.
    146     public static class TLV {
    147         private static final int SINGLE_BYTE_MAX_LENGTH = 0x80;
    148         private String tag;
    149         // Length encoding is in GPC_Specification_2.2.1: 11.1.5 APDU Message and Data Length.
    150         // Length field could be either 1 byte if length < 128, or multiple bytes with first byte
    151         // specifying how many bytes are used for length, followed by length bytes.
    152         // Bytes for the length field, in ASCII HEX string form.
    153         private String lengthBytes;
    154         // Decoded length as integer.
    155         private Integer length;
    156         private String value;
    157 
    158         public TLV(String tag) {
    159             this.tag = tag;
    160         }
    161 
    162         public String getValue() {
    163             if (value == null) return "";
    164             return value;
    165         }
    166 
    167         public String parseLength(String data) {
    168             int offset = tag.length();
    169             int firstByte = Integer.parseInt(data.substring(offset, offset + 2), 16);
    170             if (firstByte < SINGLE_BYTE_MAX_LENGTH) {
    171                 length = firstByte * 2;
    172                 lengthBytes = data.substring(offset, offset + 2);
    173             } else {
    174                 int numBytes = firstByte - SINGLE_BYTE_MAX_LENGTH;
    175                 length = Integer.parseInt(data.substring(offset + 2, offset + 2 + numBytes * 2), 16) * 2;
    176                 lengthBytes = data.substring(offset, offset + 2 + numBytes * 2);
    177             }
    178             log("TLV parseLength length=" + length + "lenghtBytes: " + lengthBytes);
    179             return lengthBytes;
    180         }
    181 
    182         public String parse(String data, boolean shouldConsumeAll) {
    183             log("Parse TLV: " + tag);
    184             if (!data.startsWith(tag)) {
    185                 throw new IllegalArgumentException("Tags don't match.");
    186             }
    187             int index = tag.length();
    188             if (index + 2 > data.length()) {
    189                 throw new IllegalArgumentException("No length.");
    190             }
    191 
    192             parseLength(data);
    193             index += lengthBytes.length();
    194 
    195             log("index="+index+" length="+length+"data.length="+data.length());
    196             int remainingLength = data.length() - (index + length);
    197             if (remainingLength < 0) {
    198                 throw new IllegalArgumentException("Not enough data.");
    199             }
    200             if (shouldConsumeAll && (remainingLength != 0)) {
    201                 throw new IllegalArgumentException("Did not consume all.");
    202             }
    203             value = data.substring(index, index + length);
    204 
    205             log("Got TLV: " + tag + "," + length + "," + value);
    206 
    207             return data.substring(index + length);
    208         }
    209     }
    210 
    211     private UiccCard mUiccCard;  // Parent
    212     private UiccPkcs15 mUiccPkcs15; // ARF fallback
    213     private AtomicInteger mState;
    214     private List<AccessRule> mAccessRules;
    215     private String mRules;
    216     private Message mLoadedCallback;
    217     private String mStatusMessage;  // Only used for debugging.
    218     private int mChannelId; // Channel Id for communicating with UICC.
    219     private int mRetryCount;  // Number of retries for open logical channel.
    220     private final Runnable mRetryRunnable = new Runnable() {
    221         @Override
    222         public void run() {
    223             openChannel();
    224         }
    225     };
    226 
    227     private void openChannel() {
    228         // Send open logical channel request.
    229         mUiccCard.iccOpenLogicalChannel(AID,
    230             obtainMessage(EVENT_OPEN_LOGICAL_CHANNEL_DONE, null));
    231     }
    232 
    233     public UiccCarrierPrivilegeRules(UiccCard uiccCard, Message loadedCallback) {
    234         log("Creating UiccCarrierPrivilegeRules");
    235         mUiccCard = uiccCard;
    236         mState = new AtomicInteger(STATE_LOADING);
    237         mStatusMessage = "Not loaded.";
    238         mLoadedCallback = loadedCallback;
    239         mRules = "";
    240         mAccessRules = new ArrayList<AccessRule>();
    241 
    242         openChannel();
    243     }
    244 
    245     /**
    246      * Returns true if the carrier privilege rules have finished loading.
    247      */
    248     public boolean areCarrierPriviligeRulesLoaded() {
    249         return mState.get() != STATE_LOADING;
    250     }
    251 
    252     /**
    253      * Returns true if the carrier privilege rules have finished loading and some rules were
    254      * specified.
    255      */
    256     public boolean hasCarrierPrivilegeRules() {
    257         return mState.get() != STATE_LOADING && mAccessRules != null && mAccessRules.size() > 0;
    258     }
    259 
    260     /**
    261      * Returns package names for privilege rules.
    262      * Return empty list if no rules defined or package name is empty string.
    263      */
    264     public List<String> getPackageNames() {
    265         List<String> pkgNames = new ArrayList<String>();
    266         if (mAccessRules != null) {
    267             for (AccessRule ar : mAccessRules) {
    268                 if(!TextUtils.isEmpty(ar.packageName)) {
    269                     pkgNames.add(ar.packageName);
    270                 }
    271             }
    272         }
    273         return pkgNames;
    274     }
    275 
    276     /**
    277      * Returns the status of the carrier privileges for the input certificate and package name.
    278      *
    279      * @param signature The signature of the certificate.
    280      * @param packageName name of the package.
    281      * @return Access status.
    282      */
    283     public int getCarrierPrivilegeStatus(Signature signature, String packageName) {
    284         int state = mState.get();
    285         if (state == STATE_LOADING) {
    286             return TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED;
    287         } else if (state == STATE_ERROR) {
    288             return TelephonyManager.CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES;
    289         }
    290 
    291         // SHA-1 is for backward compatible support only, strongly discouraged for new use.
    292         byte[] certHash = getCertHash(signature, "SHA-1");
    293         byte[] certHash256 = getCertHash(signature, "SHA-256");
    294         for (AccessRule ar : mAccessRules) {
    295             if (ar.matches(certHash, packageName) || ar.matches(certHash256, packageName)) {
    296                 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
    297             }
    298         }
    299 
    300         return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
    301     }
    302 
    303     /**
    304      * Returns the status of the carrier privileges for the input package name.
    305      *
    306      * @param packageManager PackageManager for getting signatures.
    307      * @param packageName name of the package.
    308      * @return Access status.
    309      */
    310     public int getCarrierPrivilegeStatus(PackageManager packageManager, String packageName) {
    311         try {
    312             // Short-circuit if there are no rules to check against, so we don't need to fetch
    313             // the package info with signatures.
    314             if (!hasCarrierPrivilegeRules()) {
    315                 int state = mState.get();
    316                 if (state == STATE_LOADING) {
    317                     return TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED;
    318                 } else if (state == STATE_ERROR) {
    319                     return TelephonyManager.CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES;
    320                 }
    321                 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
    322             }
    323             // Include DISABLED_UNTIL_USED components. This facilitates cases where a carrier app
    324             // is disabled by default, and some other component wants to enable it when it has
    325             // gained carrier privileges (as an indication that a matching SIM has been inserted).
    326             PackageInfo pInfo = packageManager.getPackageInfo(packageName,
    327                 PackageManager.GET_SIGNATURES | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS);
    328             return getCarrierPrivilegeStatus(pInfo);
    329         } catch (PackageManager.NameNotFoundException ex) {
    330             Rlog.e(LOG_TAG, "NameNotFoundException", ex);
    331         }
    332         return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
    333     }
    334 
    335     /**
    336      * Returns the status of the carrier privileges for the input package info.
    337      *
    338      * @param packageInfo PackageInfo for the package, containing the package signatures.
    339      * @return Access status.
    340      */
    341     public int getCarrierPrivilegeStatus(PackageInfo packageInfo) {
    342         Signature[] signatures = packageInfo.signatures;
    343         for (Signature sig : signatures) {
    344             int accessStatus = getCarrierPrivilegeStatus(sig, packageInfo.packageName);
    345             if (accessStatus != TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS) {
    346                 return accessStatus;
    347             }
    348         }
    349         return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
    350     }
    351 
    352     /**
    353      * Returns the status of the carrier privileges for the caller of the current transaction.
    354      *
    355      * @param packageManager PackageManager for getting signatures and package names.
    356      * @return Access status.
    357      */
    358     public int getCarrierPrivilegeStatusForCurrentTransaction(PackageManager packageManager) {
    359         String[] packages = packageManager.getPackagesForUid(Binder.getCallingUid());
    360 
    361         for (String pkg : packages) {
    362             int accessStatus = getCarrierPrivilegeStatus(packageManager, pkg);
    363             if (accessStatus != TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS) {
    364                 return accessStatus;
    365             }
    366         }
    367         return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
    368     }
    369 
    370     /**
    371      * Returns the package name of the carrier app that should handle the input intent.
    372      *
    373      * @param packageManager PackageManager for getting receivers.
    374      * @param intent Intent that will be sent.
    375      * @return list of carrier app package names that can handle the intent.
    376      *         Returns null if there is an error and an empty list if there
    377      *         are no matching packages.
    378      */
    379     public List<String> getCarrierPackageNamesForIntent(
    380             PackageManager packageManager, Intent intent) {
    381         List<String> packages = new ArrayList<String>();
    382         List<ResolveInfo> receivers = new ArrayList<ResolveInfo>();
    383         receivers.addAll(packageManager.queryBroadcastReceivers(intent, 0));
    384         receivers.addAll(packageManager.queryIntentContentProviders(intent, 0));
    385         receivers.addAll(packageManager.queryIntentActivities(intent, 0));
    386         receivers.addAll(packageManager.queryIntentServices(intent, 0));
    387 
    388         for (ResolveInfo resolveInfo : receivers) {
    389             String packageName = getPackageName(resolveInfo);
    390             if (packageName == null) {
    391                 continue;
    392             }
    393 
    394             int status = getCarrierPrivilegeStatus(packageManager, packageName);
    395             if (status == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
    396                 packages.add(packageName);
    397             } else if (status != TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS) {
    398                 // Any status apart from HAS_ACCESS and NO_ACCESS is considered an error.
    399                 return null;
    400             }
    401         }
    402 
    403         return packages;
    404     }
    405 
    406     @Nullable
    407     private String getPackageName(ResolveInfo resolveInfo) {
    408         if (resolveInfo.activityInfo != null) {
    409             return resolveInfo.activityInfo.packageName;
    410         } else if (resolveInfo.serviceInfo != null) {
    411             return resolveInfo.serviceInfo.packageName;
    412         } else if (resolveInfo.providerInfo != null) {
    413             return resolveInfo.providerInfo.packageName;
    414         }
    415         return null;
    416     }
    417 
    418     @Override
    419     public void handleMessage(Message msg) {
    420         AsyncResult ar;
    421 
    422         switch (msg.what) {
    423 
    424           case EVENT_OPEN_LOGICAL_CHANNEL_DONE:
    425               log("EVENT_OPEN_LOGICAL_CHANNEL_DONE");
    426               ar = (AsyncResult) msg.obj;
    427               if (ar.exception == null && ar.result != null) {
    428                   mChannelId = ((int[]) ar.result)[0];
    429                   mUiccCard.iccTransmitApduLogicalChannel(mChannelId, CLA, COMMAND, P1, P2, P3, DATA,
    430                       obtainMessage(EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE, new Integer(mChannelId)));
    431               } else {
    432                   // MISSING_RESOURCE could be due to logical channels temporarily unavailable,
    433                   // so we retry up to MAX_RETRY times, with an interval of RETRY_INTERVAL_MS.
    434                   if (ar.exception instanceof CommandException && mRetryCount < MAX_RETRY &&
    435                       ((CommandException) (ar.exception)).getCommandError() ==
    436                               CommandException.Error.MISSING_RESOURCE) {
    437                       mRetryCount++;
    438                       removeCallbacks(mRetryRunnable);
    439                       postDelayed(mRetryRunnable, RETRY_INTERVAL_MS);
    440                   } else {
    441                       // if rules cannot be read from ARA applet,
    442                       // fallback to PKCS15-based ARF.
    443                       log("No ARA, try ARF next.");
    444                       mUiccPkcs15 = new UiccPkcs15(mUiccCard,
    445                               obtainMessage(EVENT_PKCS15_READ_DONE));
    446                   }
    447               }
    448               break;
    449 
    450           case EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE:
    451               log("EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE");
    452               ar = (AsyncResult) msg.obj;
    453               if (ar.exception == null && ar.result != null) {
    454                   IccIoResult response = (IccIoResult) ar.result;
    455                   if (response.sw1 == 0x90 && response.sw2 == 0x00 &&
    456                       response.payload != null && response.payload.length > 0) {
    457                       try {
    458                           mRules += IccUtils.bytesToHexString(response.payload).toUpperCase(Locale.US);
    459                           if (isDataComplete()) {
    460                               mAccessRules = parseRules(mRules);
    461                               updateState(STATE_LOADED, "Success!");
    462                           } else {
    463                               mUiccCard.iccTransmitApduLogicalChannel(mChannelId, CLA, COMMAND, P1, P2_EXTENDED_DATA, P3, DATA,
    464                                   obtainMessage(EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE, new Integer(mChannelId)));
    465                               break;
    466                           }
    467                       } catch (IllegalArgumentException ex) {
    468                           updateState(STATE_ERROR, "Error parsing rules: " + ex);
    469                       } catch (IndexOutOfBoundsException ex) {
    470                           updateState(STATE_ERROR, "Error parsing rules: " + ex);
    471                       }
    472                    } else {
    473                       String errorMsg = "Invalid response: payload=" + response.payload +
    474                               " sw1=" + response.sw1 + " sw2=" + response.sw2;
    475                       updateState(STATE_ERROR, errorMsg);
    476                    }
    477               } else {
    478                   updateState(STATE_ERROR, "Error reading value from SIM.");
    479               }
    480 
    481               mUiccCard.iccCloseLogicalChannel(mChannelId, obtainMessage(
    482                       EVENT_CLOSE_LOGICAL_CHANNEL_DONE));
    483               mChannelId = -1;
    484               break;
    485 
    486           case EVENT_CLOSE_LOGICAL_CHANNEL_DONE:
    487               log("EVENT_CLOSE_LOGICAL_CHANNEL_DONE");
    488               break;
    489 
    490           case EVENT_PKCS15_READ_DONE:
    491               log("EVENT_PKCS15_READ_DONE");
    492               if (mUiccPkcs15 == null || mUiccPkcs15.getRules() == null) {
    493                   updateState(STATE_ERROR, "No ARA or ARF.");
    494               } else {
    495                   for (String cert : mUiccPkcs15.getRules()) {
    496                       AccessRule accessRule = new AccessRule(
    497                               IccUtils.hexStringToBytes(cert), "", 0x00);
    498                       mAccessRules.add(accessRule);
    499                   }
    500                   updateState(STATE_LOADED, "Success!");
    501               }
    502               break;
    503 
    504           default:
    505               Rlog.e(LOG_TAG, "Unknown event " + msg.what);
    506         }
    507     }
    508 
    509     /*
    510      * Check if all rule bytes have been read from UICC.
    511      * For long payload, we need to fetch it repeatly before start parsing it.
    512      */
    513     private boolean isDataComplete() {
    514         log("isDataComplete mRules:" + mRules);
    515         if (mRules.startsWith(TAG_ALL_REF_AR_DO)) {
    516             TLV allRules = new TLV(TAG_ALL_REF_AR_DO);
    517             String lengthBytes = allRules.parseLength(mRules);
    518             log("isDataComplete lengthBytes: " + lengthBytes);
    519             if (mRules.length() == TAG_ALL_REF_AR_DO.length() + lengthBytes.length() +
    520                                    allRules.length) {
    521                 log("isDataComplete yes");
    522                 return true;
    523             } else {
    524                 log("isDataComplete no");
    525                 return false;
    526             }
    527         } else {
    528             throw new IllegalArgumentException("Tags don't match.");
    529         }
    530     }
    531 
    532     /*
    533      * Parses the rules from the input string.
    534      */
    535     private static List<AccessRule> parseRules(String rules) {
    536         log("Got rules: " + rules);
    537 
    538         TLV allRefArDo = new TLV(TAG_ALL_REF_AR_DO); //FF40
    539         allRefArDo.parse(rules, true);
    540 
    541         String arDos = allRefArDo.value;
    542         List<AccessRule> accessRules = new ArrayList<AccessRule>();
    543         while (!arDos.isEmpty()) {
    544             TLV refArDo = new TLV(TAG_REF_AR_DO); //E2
    545             arDos = refArDo.parse(arDos, false);
    546             AccessRule accessRule = parseRefArdo(refArDo.value);
    547             if (accessRule != null) {
    548                 accessRules.add(accessRule);
    549             } else {
    550               Rlog.e(LOG_TAG, "Skip unrecognized rule." + refArDo.value);
    551             }
    552         }
    553         return accessRules;
    554     }
    555 
    556     /*
    557      * Parses a single rule.
    558      */
    559     private static AccessRule parseRefArdo(String rule) {
    560         log("Got rule: " + rule);
    561 
    562         String certificateHash = null;
    563         String packageName = null;
    564         String tmp = null;
    565         long accessType = 0;
    566 
    567         while (!rule.isEmpty()) {
    568             if (rule.startsWith(TAG_REF_DO)) {
    569                 TLV refDo = new TLV(TAG_REF_DO); //E1
    570                 rule = refDo.parse(rule, false);
    571 
    572                 // Skip unrelated rules.
    573                 if (!refDo.value.startsWith(TAG_DEVICE_APP_ID_REF_DO)) {
    574                     return null;
    575                 }
    576 
    577                 TLV deviceDo = new TLV(TAG_DEVICE_APP_ID_REF_DO); //C1
    578                 tmp = deviceDo.parse(refDo.value, false);
    579                 certificateHash = deviceDo.value;
    580 
    581                 if (!tmp.isEmpty()) {
    582                   if (!tmp.startsWith(TAG_PKG_REF_DO)) {
    583                       return null;
    584                   }
    585                   TLV pkgDo = new TLV(TAG_PKG_REF_DO); //CA
    586                   pkgDo.parse(tmp, true);
    587                   packageName = new String(IccUtils.hexStringToBytes(pkgDo.value));
    588                 } else {
    589                   packageName = null;
    590                 }
    591             } else if (rule.startsWith(TAG_AR_DO)) {
    592                 TLV arDo = new TLV(TAG_AR_DO); //E3
    593                 rule = arDo.parse(rule, false);
    594 
    595                 // Skip unrelated rules.
    596                 if (!arDo.value.startsWith(TAG_PERM_AR_DO)) {
    597                     return null;
    598                 }
    599 
    600                 TLV permDo = new TLV(TAG_PERM_AR_DO); //DB
    601                 permDo.parse(arDo.value, true);
    602             } else  {
    603                 // Spec requires it must be either TAG_REF_DO or TAG_AR_DO.
    604                 throw new RuntimeException("Invalid Rule type");
    605             }
    606         }
    607 
    608         AccessRule accessRule = new AccessRule(IccUtils.hexStringToBytes(certificateHash),
    609             packageName, accessType);
    610         return accessRule;
    611     }
    612 
    613     /*
    614      * Converts a Signature into a Certificate hash usable for comparison.
    615      */
    616     private static byte[] getCertHash(Signature signature, String algo) {
    617         try {
    618             MessageDigest md = MessageDigest.getInstance(algo);
    619             return md.digest(signature.toByteArray());
    620         } catch (NoSuchAlgorithmException ex) {
    621             Rlog.e(LOG_TAG, "NoSuchAlgorithmException: " + ex);
    622         }
    623         return null;
    624     }
    625 
    626     /*
    627      * Updates the state and notifies the UiccCard that the rules have finished loading.
    628      */
    629     private void updateState(int newState, String statusMessage) {
    630         mState.set(newState);
    631         if (mLoadedCallback != null) {
    632             mLoadedCallback.sendToTarget();
    633         }
    634 
    635         mStatusMessage = statusMessage;
    636     }
    637 
    638     private static void log(String msg) {
    639         if (DBG) Rlog.d(LOG_TAG, msg);
    640     }
    641 
    642     /**
    643      * Dumps info to Dumpsys - useful for debugging.
    644      */
    645     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    646         pw.println("UiccCarrierPrivilegeRules: " + this);
    647         pw.println(" mState=" + getStateString(mState.get()));
    648         pw.println(" mStatusMessage='" + mStatusMessage + "'");
    649         if (mAccessRules != null) {
    650             pw.println(" mAccessRules: ");
    651             for (AccessRule ar : mAccessRules) {
    652                 pw.println("  rule='" + ar + "'");
    653             }
    654         } else {
    655             pw.println(" mAccessRules: null");
    656         }
    657         if (mUiccPkcs15 != null) {
    658             pw.println(" mUiccPkcs15: " + mUiccPkcs15);
    659             mUiccPkcs15.dump(fd, pw, args);
    660         } else {
    661             pw.println(" mUiccPkcs15: null");
    662         }
    663         pw.flush();
    664     }
    665 
    666     /*
    667      * Converts state into human readable format.
    668      */
    669     private String getStateString(int state) {
    670       switch (state) {
    671         case STATE_LOADING:
    672             return "STATE_LOADING";
    673         case STATE_LOADED:
    674             return "STATE_LOADED";
    675         case STATE_ERROR:
    676             return "STATE_ERROR";
    677         default:
    678             return "UNKNOWN";
    679       }
    680     }
    681 }
    682