Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e9455c22 authored by Junda Liu's avatar Junda Liu Committed by Android (Google) Code Review
Browse files

Merge "Handle long UICC rules correctly." into lmp-mr1-dev

parents b502a189 7541d468
Loading
Loading
Loading
Loading
+73 −12
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import java.io.ByteArrayInputStream;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.IllegalArgumentException;
import java.lang.IndexOutOfBoundsException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
@@ -72,6 +73,7 @@ public class UiccCarrierPrivilegeRules extends Handler {
    private static final int COMMAND = 0xCA;
    private static final int P1 = 0xFF;
    private static final int P2 = 0x40;
    private static final int P2_EXTENDED_DATA = 0x60;
    private static final int P3 = 0x00;
    private static final String DATA = "";

@@ -140,7 +142,14 @@ public class UiccCarrierPrivilegeRules extends Handler {

    // Used for parsing the data from the UICC.
    private static class TLV {
        private static final int SINGLE_BYTE_MAX_LENGTH = 0x80;
        private String tag;
        // Length encoding is in GPC_Specification_2.2.1: 11.1.5 APDU Message and Data Length.
        // Length field could be either 1 byte if length < 128, or multiple bytes with first byte
        // specifying how many bytes are used for length, followed by length bytes.
        // Bytes for the length field, in ASCII HEX string form.
        private String lengthBytes;
        // Decoded length as integer.
        private Integer length;
        private String value;

@@ -148,6 +157,22 @@ public class UiccCarrierPrivilegeRules extends Handler {
            this.tag = tag;
        }

        public String parseLength(String data) {
            int offset = tag.length();
            int firstByte = Integer.parseInt(data.substring(offset, offset + 2), 16);
            // TODO: remove second condition before launch. b/18012893
            if (firstByte < SINGLE_BYTE_MAX_LENGTH || (offset + 2 + firstByte * 2 == data.length())) {
                length = firstByte * 2;
                lengthBytes = data.substring(offset, offset + 2);
            } else {
                int numBytes = firstByte - SINGLE_BYTE_MAX_LENGTH;
                length = Integer.parseInt(data.substring(offset + 2, offset + 2 + numBytes * 2), 16) * 2;
                lengthBytes = data.substring(offset, offset + 2 + numBytes * 2);
            }
            Rlog.d(LOG_TAG, "TLV parseLength length=" + length + "lenghtBytes: " + lengthBytes);
            return lengthBytes;
        }

        public String parse(String data, boolean shouldConsumeAll) {
            Rlog.d(LOG_TAG, "Parse TLV: " + tag);
            if (!data.startsWith(tag)) {
@@ -157,10 +182,11 @@ public class UiccCarrierPrivilegeRules extends Handler {
            if (index + 2 > data.length()) {
                throw new IllegalArgumentException("No length.");
            }
            length = new Integer(2 * Integer.parseInt(
                    data.substring(index, index + 2), 16));
            index += 2;

            parseLength(data);
            index += lengthBytes.length();

            Rlog.d(LOG_TAG, "index="+index+" length="+length+"data.length="+data.length());
            int remainingLength = data.length() - (index + length);
            if (remainingLength < 0) {
                throw new IllegalArgumentException("Not enough data.");
@@ -179,8 +205,10 @@ public class UiccCarrierPrivilegeRules extends Handler {
    private UiccCard mUiccCard;  // Parent
    private AtomicInteger mState;
    private List<AccessRule> mAccessRules;
    private String mRules;
    private Message mLoadedCallback;
    private String mStatusMessage;  // Only used for debugging.
    private int mChannelId; // Channel Id for communicating with UICC.

    public UiccCarrierPrivilegeRules(UiccCard uiccCard, Message loadedCallback) {
        Rlog.d(LOG_TAG, "Creating UiccCarrierPrivilegeRules");
@@ -188,6 +216,7 @@ public class UiccCarrierPrivilegeRules extends Handler {
        mState = new AtomicInteger(STATE_LOADING);
        mStatusMessage = "Not loaded.";
        mLoadedCallback = loadedCallback;
        mRules = "";

        // Start loading the rules.
        mUiccCard.iccOpenLogicalChannel(AID,
@@ -322,9 +351,9 @@ public class UiccCarrierPrivilegeRules extends Handler {
              Rlog.d(LOG_TAG, "EVENT_OPEN_LOGICAL_CHANNEL_DONE");
              ar = (AsyncResult) msg.obj;
              if (ar.exception == null && ar.result != null) {
                  int channelId = ((int[]) ar.result)[0];
                  mUiccCard.iccTransmitApduLogicalChannel(channelId, CLA, COMMAND, P1, P2, P3, DATA,
                      obtainMessage(EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE, new Integer(channelId)));
                  mChannelId = ((int[]) ar.result)[0];
                  mUiccCard.iccTransmitApduLogicalChannel(mChannelId, CLA, COMMAND, P1, P2, P3, DATA,
                      obtainMessage(EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE, new Integer(mChannelId)));
              } else {
                  updateState(STATE_ERROR, "Error opening channel");
              }
@@ -335,12 +364,22 @@ public class UiccCarrierPrivilegeRules extends Handler {
              ar = (AsyncResult) msg.obj;
              if (ar.exception == null && ar.result != null) {
                  IccIoResult response = (IccIoResult) ar.result;
                  if (response.payload != null && response.sw1 == 0x90 && response.sw2 == 0x00) {
                  if (response.sw1 == 0x90 && response.sw2 == 0x00 &&
                      response.payload != null && response.payload.length > 0) {
                      try {
                          mAccessRules = parseRules(IccUtils.bytesToHexString(response.payload));
                          updateState(STATE_LOADED, "Loaded successfully");
                          mRules += IccUtils.bytesToHexString(response.payload).toUpperCase(Locale.US);
                          if (isDataComplete()) {
                              mAccessRules = parseRules(mRules);
                              updateState(STATE_LOADED, "Success!");
                          } else {
                              mUiccCard.iccTransmitApduLogicalChannel(mChannelId, CLA, COMMAND, P1, P2_EXTENDED_DATA, P3, DATA,
                                  obtainMessage(EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE, new Integer(mChannelId)));
                              break;
                          }
                      } catch (IllegalArgumentException ex) {
                          updateState(STATE_ERROR, "Error parsing rules: " + ex);
                      } catch (IndexOutOfBoundsException ex) {
                          updateState(STATE_ERROR, "Error parsing rules: " + ex);
                      }
                   } else {
                      String errorMsg = "Invalid response: payload=" + response.payload +
@@ -351,9 +390,9 @@ public class UiccCarrierPrivilegeRules extends Handler {
                  updateState(STATE_ERROR, "Error reading value from SIM.");
              }

              int channelId = (Integer) ar.userObj;
              mUiccCard.iccCloseLogicalChannel(channelId, obtainMessage(
              mUiccCard.iccCloseLogicalChannel(mChannelId, obtainMessage(
                      EVENT_CLOSE_LOGICAL_CHANNEL_DONE));
              mChannelId = -1;
              break;

          case EVENT_CLOSE_LOGICAL_CHANNEL_DONE:
@@ -365,11 +404,33 @@ public class UiccCarrierPrivilegeRules extends Handler {
        }
    }

    /*
     * Check if all rule bytes have been read from UICC.
     * For long payload, we need to fetch it repeatly before start parsing it.
     */
    private boolean isDataComplete() {
        Rlog.d(LOG_TAG, "isDataComplete mRules:" + mRules);
        if (mRules.startsWith(TAG_ALL_REF_AR_DO)) {
            TLV allRules = new TLV(TAG_ALL_REF_AR_DO);
            String lengthBytes = allRules.parseLength(mRules);
            Rlog.d(LOG_TAG, "isDataComplete lengthBytes: " + lengthBytes);
            if (mRules.length() == TAG_ALL_REF_AR_DO.length() + lengthBytes.length() +
                                   allRules.length) {
                Rlog.d(LOG_TAG, "isDataComplete yes");
                return true;
            } else {
                Rlog.d(LOG_TAG, "isDataComplete no");
                return false;
            }
        } else {
            throw new IllegalArgumentException("Tags don't match.");
        }
    }

    /*
     * Parses the rules from the input string.
     */
    private static List<AccessRule> parseRules(String rules) {
        rules = rules.toUpperCase(Locale.US);
        Rlog.d(LOG_TAG, "Got rules: " + rules);

        TLV allRefArDo = new TLV(TAG_ALL_REF_AR_DO); //FF40