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