UiccCarrierPrivilegeRules.java revision 4baf17fd699249d1b387903b6db7328ad3f7b3e2
14baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal/*
24baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * Copyright (C) 2014 The Android Open Source Project
34baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal *
44baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * Licensed under the Apache License, Version 2.0 (the "License");
54baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * you may not use this file except in compliance with the License.
64baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * You may obtain a copy of the License at
74baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal *
84baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal *      http://www.apache.org/licenses/LICENSE-2.0
94baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal *
104baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * Unless required by applicable law or agreed to in writing, software
114baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * distributed under the License is distributed on an "AS IS" BASIS,
124baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * See the License for the specific language governing permissions and
144baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * limitations under the License.
154baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal */
164baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
174baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalpackage com.android.internal.telephony.uicc;
184baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
194baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalimport android.content.pm.Signature;
204baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalimport android.os.AsyncResult;
214baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalimport android.os.Handler;
224baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalimport android.os.Message;
234baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalimport android.telephony.Rlog;
244baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalimport android.telephony.TelephonyManager;
254baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
264baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalimport com.android.internal.telephony.CommandsInterface;
274baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalimport com.android.internal.telephony.uicc.IccUtils;
284baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
294baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalimport java.io.ByteArrayInputStream;
304baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalimport java.lang.IllegalArgumentException;
314baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalimport java.security.MessageDigest;
324baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalimport java.security.NoSuchAlgorithmException;
334baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalimport java.security.cert.Certificate;
344baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalimport java.security.cert.CertificateException;
354baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalimport java.security.cert.CertificateFactory;
364baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalimport java.security.cert.X509Certificate;
374baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalimport java.util.ArrayList;
384baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalimport java.util.concurrent.atomic.AtomicInteger;
394baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalimport java.util.Arrays;
404baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalimport java.util.List;
414baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalimport java.util.Locale;
424baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
434baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal/**
444baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * Class that reads and stores the carrier privileged rules from the UICC.
454baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal *
464baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * The rules are read when the class is created, hence it should only be created
474baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * after the UICC can be read. And it should be deleted when a UICC is changed.
484baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal *
494baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * The spec for the rules:
504baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal *     TODO: Put link here.
514baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal *
524baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal *
534baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * TODO: Notifications.
544baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal *
554baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * {@hide}
564baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal */
574baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalpublic class UiccCarrierPrivilegeRules extends Handler {
584baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private static final String LOG_TAG = "UiccCarrierPrivilegeRules";
594baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
604baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    // TODO: These are temporary values. Put real ones here.
614baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private static final String AID = "A0000000015141434D";
624baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private static final int CLA = 0x80;
634baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private static final int COMMAND = 0xCA;
644baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private static final int P1 = 0xFF;
654baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private static final int P2 = 0x40;
664baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private static final int P3 = 0x00;
674baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private static final String DATA = "";
684baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
694baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    // Values from the data standard.
704baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private static final String TAG_ALL_REF_AR_DO = "FF40";
714baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private static final String TAG_REF_AR_DO = "E2";
724baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private static final String TAG_REF_DO = "E1";
734baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private static final String TAG_AR_DO = "E3";
744baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private static final String TAG_DEVICE_APP_ID_REF_DO = "C1";
754baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private static final String TAG_PERM_AR_DO = "DB";
764baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private static final String TAG_PKG_REF_DO = "CA";
774baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
784baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private static final int EVENT_OPEN_LOGICAL_CHANNEL_DONE = 1;
794baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private static final int EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE = 2;
804baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private static final int EVENT_CLOSE_LOGICAL_CHANNEL_DONE = 3;
814baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
824baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    // State of the object.
834baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private static final int STATE_LOADING  = 0;
844baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private static final int STATE_LOADED   = 1;
854baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private static final int STATE_ERROR    = 2;
864baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
874baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    // Describes a single rule.
884baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private static class AccessRule {
894baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        public byte[] certificateHash;
904baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        public String packageName;
914baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        public long accessType;   // This bit is not currently used, but reserved for future use.
924baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
934baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        AccessRule(byte[] certificateHash, String packageName, long accessType) {
944baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            this.certificateHash = certificateHash;
954baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            this.packageName = packageName;
964baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            this.accessType = accessType;
974baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        }
984baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
994baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        boolean matches(byte[] certHash, String packageName) {
1004baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal          return certHash != null && Arrays.equals(this.certificateHash, certHash) &&
1014baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                (this.packageName == null || this.packageName.equals(packageName));
1024baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        }
1034baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
1044baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        @Override
1054baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        public String toString() {
1064baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            return "cert: " + certificateHash + " pkg: " + packageName +
1074baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                " access: " + accessType;
1084baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        }
1094baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    }
1104baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
1114baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    // Used for parsing the data from the UICC.
1124baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private static class TLV {
1134baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        private String tag;
1144baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        private Integer length;
1154baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        private String value;
1164baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
1174baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        public TLV(String tag) {
1184baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            this.tag = tag;
1194baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        }
1204baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
1214baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        public String parse(String data, boolean shouldConsumeAll) {
1224baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            if (!data.startsWith(tag)) {
1234baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                throw new IllegalArgumentException("Tags don't match.");
1244baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            }
1254baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            int index = tag.length();
1264baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            if (index + 2 > data.length()) {
1274baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                throw new IllegalArgumentException("No length.");
1284baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            }
1294baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            length = new Integer(2 * Integer.parseInt(
1304baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                    data.substring(index, index + 2), 16));
1314baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            index += 2;
1324baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
1334baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            int remainingLength = data.length() - (index + length);
1344baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            if (remainingLength < 0) {
1354baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                throw new IllegalArgumentException("Not enough data.");
1364baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            }
1374baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            if (shouldConsumeAll && (remainingLength != 0)) {
1384baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                throw new IllegalArgumentException("Did not consume all.");
1394baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            }
1404baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            value = data.substring(index, index + length);
1414baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
1424baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            Rlog.e(LOG_TAG, "Got TLV: " + tag + "," + length + "," + value);
1434baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
1444baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            return data.substring(index + length);
1454baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        }
1464baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    }
1474baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
1484baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private UiccCard mUiccCard;  // Parent
1494baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private AtomicInteger mState;
1504baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private List<AccessRule> mAccessRules;
1514baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
1524baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    public UiccCarrierPrivilegeRules(UiccCard uiccCard) {
1534baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        Rlog.d(LOG_TAG, "Creating UiccCarrierPrivilegeRules");
1544baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        mUiccCard = uiccCard;
1554baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        mState = new AtomicInteger(STATE_LOADING);
1564baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
1574baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        // Start loading the rules.
1584baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        mUiccCard.iccOpenLogicalChannel(AID,
1594baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            obtainMessage(EVENT_OPEN_LOGICAL_CHANNEL_DONE, null));
1604baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    }
1614baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
1624baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    /**
1634baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal     * Returns true if the certificate and packageName has carrier privileges.
1644baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal     *
1654baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal     * @param signature The signature of the certificate.
1664baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal     * @param packageName name of the package.
1674baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal     * @return Access status.
1684baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal     */
1694baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    public int hasCarrierPrivileges(Signature signature, String packageName) {
1704baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        Rlog.d(LOG_TAG, "hasCarrierPrivileges: " + signature + " : " + packageName);
1714baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        int state = mState.get();
1724baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        if (state == STATE_LOADING) {
1734baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            Rlog.d(LOG_TAG, "Rules not loaded.");
1744baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            return TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED;
1754baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        } else if (state == STATE_ERROR) {
1764baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            Rlog.d(LOG_TAG, "Error loading rules.");
1774baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            return TelephonyManager.CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES;
1784baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        }
1794baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
1804baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        byte[] certHash = getCertHash(signature);
1814baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        if (certHash == null) {
1824baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal          return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
1834baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        }
1844baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        Rlog.e(LOG_TAG, "Checking: " + IccUtils.bytesToHexString(certHash) + " : " + packageName);
1854baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
1864baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        for (AccessRule ar : mAccessRules) {
1874baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            if (ar.matches(certHash, packageName)) {
1884baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                return TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
1894baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            }
1904baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        }
1914baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
1924baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        Rlog.d(LOG_TAG, "No matching rule found. Returning false.");
1934baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
1944baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    }
1954baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
1964baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    @Override
1974baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    public void handleMessage(Message msg) {
1984baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        AsyncResult ar;
1994baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
2004baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        switch (msg.what) {
2014baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
2024baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal          case EVENT_OPEN_LOGICAL_CHANNEL_DONE:
2034baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal              Rlog.d(LOG_TAG, "EVENT_OPEN_LOGICAL_CHANNEL_DONE");
2044baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal              ar = (AsyncResult) msg.obj;
2054baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal              if (ar.exception == null && ar.result != null) {
2064baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                  int channelId = ((int[]) ar.result)[0];
2074baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                  mUiccCard.iccTransmitApduLogicalChannel(channelId, CLA, COMMAND, P1, P2, P3, DATA,
2084baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                      obtainMessage(EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE, new Integer(channelId)));
2094baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal              } else {
2104baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                  Rlog.e(LOG_TAG, "Error opening channel");
2114baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                  mState.set(STATE_ERROR);
2124baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal              }
2134baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal              break;
2144baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
2154baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal          case EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE:
2164baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal              Rlog.d(LOG_TAG, "EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE");
2174baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal              ar = (AsyncResult) msg.obj;
2184baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal              if (ar.exception == null && ar.result != null) {
2194baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                  IccIoResult response = (IccIoResult) ar.result;
2204baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                  if (response.payload != null && response.sw1 == 0x90 && response.sw2 == 0x00) {
2214baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                      try {
2224baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                          mAccessRules = parseRules(IccUtils.bytesToHexString(response.payload));
2234baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                          mState.set(STATE_LOADED);
2244baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                      } catch (IllegalArgumentException ex) {
2254baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                          Rlog.e(LOG_TAG, "Error parsing rules: " + ex);
2264baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                          mState.set(STATE_ERROR);
2274baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                      }
2284baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                   } else {
2294baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                      Rlog.e(LOG_TAG, "Invalid response: payload=" + response.payload +
2304baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                              " sw1=" + response.sw1 + " sw2=" + response.sw2);
2314baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                   }
2324baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal              } else {
2334baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                  Rlog.e(LOG_TAG, "Error reading value from SIM.");
2344baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                  mState.set(STATE_ERROR);
2354baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal              }
2364baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
2374baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal              int channelId = (Integer) ar.userObj;
2384baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal              mUiccCard.iccCloseLogicalChannel(channelId, obtainMessage(
2394baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                      EVENT_CLOSE_LOGICAL_CHANNEL_DONE));
2404baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal              break;
2414baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
2424baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal          case EVENT_CLOSE_LOGICAL_CHANNEL_DONE:
2434baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal              Rlog.d(LOG_TAG, "EVENT_CLOSE_LOGICAL_CHANNEL_DONE");
2444baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal              break;
2454baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
2464baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal          default:
2474baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal              Rlog.e(LOG_TAG, "Unknown event " + msg.what);
2484baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        }
2494baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    }
2504baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
2514baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    /*
2524baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal     * Parses the rules from the input string.
2534baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal     */
2544baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private static List<AccessRule> parseRules(String rules) {
2554baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        rules = rules.toUpperCase(Locale.US);
2564baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        Rlog.d(LOG_TAG, "Got rules: " + rules);
2574baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
2584baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        /*
2594baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal         * Rules format.
2604baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal         *   ALL_REF_AR_DO = TAG_ALL_REF_AR_DO + len + [REF_AR_DO]xn
2614baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal         *   REF_AR_DO = TAG_REF_AR_DO + len + REF-DO | AR-DO
2624baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal         */
2634baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        TLV allRefArDo = new TLV(TAG_ALL_REF_AR_DO);
2644baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        allRefArDo.parse(rules, true);
2654baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
2664baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        String arDos = allRefArDo.value;
2674baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        List<AccessRule> accessRules = new ArrayList<AccessRule>();
2684baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        while (!arDos.isEmpty()) {
2694baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            TLV refArDo = new TLV(TAG_REF_AR_DO);
2704baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            arDos = refArDo.parse(arDos, false);
2714baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            accessRules.add(parseRefArdo(refArDo.value));
2724baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        }
2734baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        return accessRules;
2744baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    }
2754baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
2764baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    /*
2774baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal     * Parses a single rule.
2784baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal     */
2794baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private static AccessRule parseRefArdo(String rule) {
2804baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        Rlog.d(LOG_TAG, "Got rule: " + rule);
2814baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
2824baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        /*
2834baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal         *   REF_AR_DO = TAG_REF_AR_DO + len + REF-DO | AR-DO
2844baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal         *   REF_DO = TAG_REF_DO + len + DEVICE_APP_ID_REF_DO | PKG_REF_DO
2854baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal         *   AR_DO = TAG_AR_DO + len + PERM_AR_DO
2864baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal         *   DEVICE_APP_ID_REF_DO = TAG_DEVICE_APP_ID_REF_DO + 20 | 0 + 20 byte hash (padded with FF)
2874baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal         *   PKG_REF_DO = TAG_PKG_REF_DO + 20 + 20 byte hash of package name (padded with FF)
2884baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal         *   PERM_AR_DO = TAG_PERM_AR_DO + 8 + 8 bytes
2894baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal         */
2904baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
2914baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        String certificateHash = null;
2924baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        String packageName = null;
2934baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        long accessType = 0;
2944baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
2954baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        while (!rule.isEmpty()) {
2964baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            if (rule.startsWith(TAG_REF_DO)) {
2974baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                TLV refDo = new TLV(TAG_REF_DO);
2984baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                rule = refDo.parse(rule, false);
2994baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
3004baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                if (refDo.value.startsWith(TAG_DEVICE_APP_ID_REF_DO)) {
3014baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                    TLV deviceDo = new TLV(TAG_DEVICE_APP_ID_REF_DO);
3024baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                    deviceDo.parse(refDo.value, true);
3034baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                    certificateHash = deviceDo.value;
3044baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                } else if (refDo.value.startsWith(TAG_PKG_REF_DO)) {
3054baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                    TLV pkgDo = new TLV(TAG_PKG_REF_DO);
3064baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                    pkgDo.parse(refDo.value, true);
3074baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                    packageName = pkgDo.value;
3084baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                } else {
3094baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                    throw new IllegalArgumentException(
3104baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                        "Invalid REF_DO value tag: " + refDo.value);
3114baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                }
3124baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            } else if (rule.startsWith(TAG_AR_DO)) {
3134baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                TLV arDo = new TLV(TAG_AR_DO);
3144baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                rule = arDo.parse(rule, false);
3154baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
3164baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                TLV permDo = new TLV(TAG_PERM_AR_DO);
3174baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                permDo.parse(arDo.value, true);
3184baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                Rlog.e(LOG_TAG, permDo.value);
3194baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            } else  {
3204baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                // TODO: Mayabe just throw away rules that are not parseable.
3214baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                throw new RuntimeException("Invalid Rule type");
3224baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            }
3234baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        }
3244baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
3254baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        Rlog.e(LOG_TAG, "Adding: " + certificateHash + " : " + packageName + " : " + accessType);
3264baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
3274baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        AccessRule accessRule = new AccessRule(IccUtils.hexStringToBytes(certificateHash),
3284baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            packageName, accessType);
3294baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        Rlog.e(LOG_TAG, "Parsed rule: " + accessRule);
3304baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        return accessRule;
3314baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    }
3324baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
3334baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    /*
3344baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal     * Converts a Signature into a Certificate hash usable for comparison.
3354baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal     */
3364baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private static byte[] getCertHash(Signature signature) {
3374baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        // TODO: Is the following sufficient.
3384baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        try {
3394baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
3404baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            X509Certificate cert = (X509Certificate) certFactory.generateCertificate(
3414baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                    new ByteArrayInputStream(signature.toByteArray()));
3424baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
3434baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            MessageDigest md = MessageDigest.getInstance("SHA");
3444baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            return md.digest(cert.getEncoded());
3454baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        } catch (CertificateException ex) {
3464baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            Rlog.e(LOG_TAG, "CertificateException: " + ex);
3474baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        } catch (NoSuchAlgorithmException ex) {
3484baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            Rlog.e(LOG_TAG, "NoSuchAlgorithmException: " + ex);
3494baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        }
3504baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
3514baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        Rlog.e(LOG_TAG, "Cannot compute cert hash");
3524baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        return null;
3534baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    }
3544baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal}
355