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.annotation.Nullable;
20import android.content.Intent;
21import android.content.pm.PackageInfo;
22import android.content.pm.PackageManager;
23import android.content.pm.ResolveInfo;
24import android.content.pm.Signature;
25import android.os.AsyncResult;
26import android.os.Binder;
27import android.os.Handler;
28import android.os.Message;
29import android.telephony.Rlog;
30import android.telephony.TelephonyManager;
31import android.text.TextUtils;
32
33import com.android.internal.telephony.CommandException;
34import com.android.internal.telephony.CommandsInterface;
35import com.android.internal.telephony.uicc.IccUtils;
36
37import java.io.ByteArrayInputStream;
38import java.io.FileDescriptor;
39import java.io.PrintWriter;
40import java.lang.IllegalArgumentException;
41import java.lang.IndexOutOfBoundsException;
42import java.security.MessageDigest;
43import java.security.NoSuchAlgorithmException;
44import java.security.cert.Certificate;
45import java.security.cert.CertificateException;
46import java.security.cert.CertificateFactory;
47import java.security.cert.X509Certificate;
48import java.util.ArrayList;
49import java.util.Arrays;
50import java.util.List;
51import java.util.Locale;
52import 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 */
64public 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