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

Commit 512a7d2e authored by Jordan Liu's avatar Jordan Liu
Browse files

Use carrier key from carrier config

When no key is available, check if a public carrier key is stored in
carrier config as a backup for the carrier.

Bug: 175801497
Test: manual and atest TelephonyManagerTest
Change-Id: I8e855cca847d65276bfb34a797f5a2fd076a0763
Merged-In: I8e855cca847d65276bfb34a797f5a2fd076a0763
parent e6ddbafd
Loading
Loading
Loading
Loading
+61 −3
Original line number Diff line number Diff line
@@ -22,16 +22,20 @@ import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteConstraintException;
import android.os.PersistableBundle;
import android.os.UserHandle;
import android.provider.Telephony;
import android.telephony.CarrierConfigManager;
import android.telephony.ImsiEncryptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;

import com.android.internal.telephony.metrics.TelephonyMetrics;

import java.security.PublicKey;
import java.util.Date;

/**
@@ -47,6 +51,10 @@ public class CarrierInfoManager {
    */
    private static final int RESET_CARRIER_KEY_RATE_LIMIT = 12 * 60 * 60 * 1000;

    // Key ID used with the backup key from carrier config
    private static final String EPDG_BACKUP_KEY_ID = "backup_key_from_carrier_config_epdg";
    private static final String WLAN_BACKUP_KEY_ID = "backup_key_from_carrier_config_wlan";

    // Last time the resetCarrierKeysForImsiEncryption API was called successfully.
    private long mLastAccessResetCarrierKey = 0;

@@ -54,18 +62,21 @@ public class CarrierInfoManager {
     * Returns Carrier specific information that will be used to encrypt the IMSI and IMPI.
     * @param keyType whether the key is being used for WLAN or ePDG.
     * @param context
     * @param fallback whether to fallback to the IMSI key info stored in carrier config
     * @return ImsiEncryptionInfo which contains the information, including the public key, to be
     *         used for encryption.
     */
    public static ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int keyType,
                                                                     Context context,
                                                                     String operatorNumeric) {
                                                                     String operatorNumeric,
                                                                     boolean fallback,
                                                                     int subId) {
        String mcc = "";
        String mnc = "";
        if (!TextUtils.isEmpty(operatorNumeric)) {
            mcc = operatorNumeric.substring(0, 3);
            mnc = operatorNumeric.substring(3);
            Log.i(LOG_TAG, "using values for mnc, mcc: " + mnc + "," + mcc);
            Log.i(LOG_TAG, "using values for mcc, mnc: " + mcc + "," + mnc);
        } else {
            Log.e(LOG_TAG, "Invalid networkOperator: " + operatorNumeric);
            return null;
@@ -83,8 +94,55 @@ public class CarrierInfoManager {
                    new String[]{mcc, mnc, String.valueOf(keyType)}, null);
            if (findCursor == null || !findCursor.moveToFirst()) {
                Log.d(LOG_TAG, "No rows found for keyType: " + keyType);
                if (!fallback) {
                    Log.d(LOG_TAG, "Skipping fallback logic");
                    return null;
                }
                // return carrier config key as fallback
                CarrierConfigManager carrierConfigManager = (CarrierConfigManager)
                        context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
                if (carrierConfigManager == null) {
                    Log.d(LOG_TAG, "Could not get CarrierConfigManager for backup key");
                    return null;
                }
                if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
                    Log.d(LOG_TAG, "Could not get carrier config with invalid subId");
                    return null;
                }
                PersistableBundle b = carrierConfigManager.getConfigForSubId(subId);
                if (b == null) {
                    Log.d(LOG_TAG, "Could not get carrier config bundle for backup key");
                    return null;
                }
                int keyAvailabilityBitmask = b.getInt(
                        CarrierConfigManager.IMSI_KEY_AVAILABILITY_INT);
                if (!CarrierKeyDownloadManager.isKeyEnabled(keyType, keyAvailabilityBitmask)) {
                    Log.d(LOG_TAG, "Backup key does not have matching keyType. keyType=" + keyType
                            + " keyAvailability=" + keyAvailabilityBitmask);
                    return null;
                }
                String keyString = null;
                String keyId = null;
                if (keyType == TelephonyManager.KEY_TYPE_EPDG) {
                    keyString = b.getString(
                            CarrierConfigManager.IMSI_CARRIER_PUBLIC_KEY_EPDG_STRING);
                    keyId = EPDG_BACKUP_KEY_ID;
                } else if (keyType == TelephonyManager.KEY_TYPE_WLAN) {
                    keyString = b.getString(
                            CarrierConfigManager.IMSI_CARRIER_PUBLIC_KEY_WLAN_STRING);
                    keyId = WLAN_BACKUP_KEY_ID;
                }
                if (TextUtils.isEmpty(keyString)) {
                    Log.d(LOG_TAG,
                            "Could not get carrier config key string for backup key. keyType="
                                    + keyType);
                    return null;
                }
                Pair<PublicKey, Long> keyInfo =
                        CarrierKeyDownloadManager.getKeyInformation(keyString.getBytes());
                return new ImsiEncryptionInfo(mcc, mnc, keyType, keyId,
                        keyInfo.first, new Date(keyInfo.second));
            }
            if (findCursor.getCount() > 1) {
                Log.e(LOG_TAG, "More than 1 row found for the keyType: " + keyType);
            }
+22 −10
Original line number Diff line number Diff line
@@ -184,7 +184,7 @@ public class CarrierKeyDownloadManager extends Handler {
        if (carrierUsesKeys()) {
            if (areCarrierKeysAbsentOrExpiring()) {
                boolean downloadStartedSuccessfully = downloadKey();
                // if the download was attemped, but not started successfully, and if carriers uses
                // if the download was attempted, but not started successfully, and if carriers uses
                // keys, we'll still want to renew the alarms, and try downloading the key a day
                // later.
                if (!downloadStartedSuccessfully) {
@@ -229,7 +229,7 @@ public class CarrierKeyDownloadManager extends Handler {
                continue;
            }
            ImsiEncryptionInfo imsiEncryptionInfo =
                    mPhone.getCarrierInfoForImsiEncryption(key_type);
                    mPhone.getCarrierInfoForImsiEncryption(key_type, false);
            if (imsiEncryptionInfo != null && imsiEncryptionInfo.getExpirationTime() != null) {
                if (minExpirationDate > imsiEncryptionInfo.getExpirationTime().getTime()) {
                    minExpirationDate = imsiEncryptionInfo.getExpirationTime().getTime();
@@ -273,7 +273,7 @@ public class CarrierKeyDownloadManager extends Handler {
        PendingIntent carrierKeyDownloadIntent = PendingIntent.getBroadcast(mContext, 0, intent,
                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
        alarmManager.set(AlarmManager.RTC_WAKEUP, minExpirationDate, carrierKeyDownloadIntent);
        Log.d(LOG_TAG, "setRenewelAlarm: action=" + intent.getAction() + " time="
        Log.d(LOG_TAG, "setRenewalAlarm: action=" + intent.getAction() + " time="
                + new Date(minExpirationDate));
    }

@@ -389,8 +389,10 @@ public class CarrierKeyDownloadManager extends Handler {
        mURL = b.getString(CarrierConfigManager.IMSI_KEY_DOWNLOAD_URL_STRING);
        mAllowedOverMeteredNetwork = b.getBoolean(
                KEY_ALLOW_METERED_NETWORK_FOR_CERT_DOWNLOAD_BOOL);
        if (TextUtils.isEmpty(mURL) || mKeyAvailability == 0) {
            Log.d(LOG_TAG, "Carrier not enabled or invalid values");
        if (mKeyAvailability == 0 || TextUtils.isEmpty(mURL)) {
            Log.d(LOG_TAG,
                    "Carrier not enabled or invalid values. mKeyAvailability=" + mKeyAvailability
                            + " mURL=" + mURL);
            return false;
        }
        for (int key_type : CARRIER_KEY_TYPES) {
@@ -485,7 +487,16 @@ public class CarrierKeyDownloadManager extends Handler {
    @VisibleForTesting
    public boolean isKeyEnabled(int keyType) {
        // since keytype has values of 1, 2.... we need to subtract 1 from the keytype.
        int returnValue = (mKeyAvailability >> (keyType - 1)) & 1;
        return isKeyEnabled(keyType, mKeyAvailability);
    }

    /**
     * introspects the mKeyAvailability bitmask
     * @return true if the digit at position k is 1, else false.
     */
    public static boolean isKeyEnabled(int keyType, int keyAvailability) {
        // since keytype has values of 1, 2.... we need to subtract 1 from the keytype.
        int returnValue = (keyAvailability >> (keyType - 1)) & 1;
        return (returnValue == 1) ? true : false;
    }

@@ -500,8 +511,10 @@ public class CarrierKeyDownloadManager extends Handler {
            if (!isKeyEnabled(key_type)) {
                continue;
            }
            // get encryption info with fallback=false so that we attempt a download even if there's
            // backup info stored in carrier config
            ImsiEncryptionInfo imsiEncryptionInfo =
                    mPhone.getCarrierInfoForImsiEncryption(key_type);
                    mPhone.getCarrierInfoForImsiEncryption(key_type, false);
            if (imsiEncryptionInfo == null) {
                Log.d(LOG_TAG, "Key not found for: " + key_type);
                return true;
@@ -533,7 +546,6 @@ public class CarrierKeyDownloadManager extends Handler {
            // TODO(b/128550341): Implement the logic to minimize using metered network such as
            // LTE for downloading a certificate.
            request.setAllowedOverMetered(mAllowedOverMeteredNetwork);
            request.setVisibleInDownloadsUi(false);
            request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN);
            request.addRequestHeader("Accept-Encoding", "gzip");
            Long carrierKeyDownloadRequestId = mDownloadManager.enqueue(request);
@@ -546,7 +558,7 @@ public class CarrierKeyDownloadManager extends Handler {
            editor.putString(MCC_MNC_PREF_TAG + slotId, mccMnc);
            editor.commit();
        } catch (Exception e) {
            Log.e(LOG_TAG, "exception trying to dowload key from url: " + mURL);
            Log.e(LOG_TAG, "exception trying to download key from url: " + mURL);
            return false;
        }
        return true;
+2 −2
Original line number Diff line number Diff line
@@ -1842,11 +1842,11 @@ public class GsmCdmaPhone extends Phone {
    }

    @Override
    public ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int keyType) {
    public ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int keyType, boolean fallback) {
        String operatorNumeric = TelephonyManager.from(mContext)
                .getSimOperatorNumericForPhone(mPhoneId);
        return CarrierInfoManager.getCarrierInfoForImsiEncryption(keyType,
                mContext, operatorNumeric);
                mContext, operatorNumeric, fallback, getSubId());
    }

    @Override
+3 −1
Original line number Diff line number Diff line
@@ -3664,12 +3664,14 @@ public abstract class Phone extends Handler implements PhoneInternalInterface {
    /**
     * Returns Carrier specific information that will be used to encrypt the IMSI and IMPI.
     * @param keyType whether the key is being used for WLAN or ePDG.
     * @param fallback whether or not to fall back to the encryption key info stored in carrier
     *                 config
     * @return ImsiEncryptionInfo which includes the Key Type, the Public Key
     *        {@link java.security.PublicKey} and the Key Identifier.
     *        The keyIdentifier This is used by the server to help it locate the private key to
     *        decrypt the permanent identity.
     */
    public ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int keyType) {
    public ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int keyType, boolean fallback) {
        return null;
    }

+2 −1
Original line number Diff line number Diff line
@@ -936,12 +936,13 @@ public interface PhoneInternalInterface {
    /**
     * Returns Carrier specific information that will be used to encrypt the IMSI and IMPI.
     * @param keyType whether the key is being used for WLAN or ePDG.
     * @param fallback whether to fall back to the encryption key stored in carrier config
     * @return ImsiEncryptionInfo which includes the Key Type, the Public Key
     *        {@link java.security.PublicKey} and the Key Identifier.
     *        The keyIdentifier This is used by the server to help it locate the private key to
     *        decrypt the permanent identity.
     */
    public ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int keyType);
    ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int keyType, boolean fallback);

    /**
     * Resets the Carrier Keys, by deleting them from the database and sending a download intent.
Loading