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