diff options
Diffstat (limited to 'service')
6 files changed, 238 insertions, 146 deletions
diff --git a/service/java/com/android/server/wifi/ClientModeImpl.java b/service/java/com/android/server/wifi/ClientModeImpl.java index 720b3dccb..68dfe083e 100644 --- a/service/java/com/android/server/wifi/ClientModeImpl.java +++ b/service/java/com/android/server/wifi/ClientModeImpl.java @@ -89,7 +89,6 @@ import android.os.WorkSource; import android.provider.Settings; import android.system.OsConstants; import android.telephony.SubscriptionManager; -import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Log; import android.util.Pair; @@ -233,6 +232,8 @@ public class ClientModeImpl extends StateMachine { private int mLastSignalLevel = -1; private String mLastBssid; private int mLastNetworkId; // The network Id we successfully joined + // The subId used by WifiConfiguration with SIM credential which was connected successfully + private int mLastSubId; private boolean mIpReachabilityDisconnectEnabled = true; @@ -676,16 +677,10 @@ public class ClientModeImpl extends StateMachine { */ public static final WorkSource WIFI_WORK_SOURCE = new WorkSource(Process.WIFI_UID); - private TelephonyManager mTelephonyManager; - private TelephonyManager getTelephonyManager() { - if (mTelephonyManager == null) { - mTelephonyManager = mWifiInjector.makeTelephonyManager(); - } - return mTelephonyManager; - } - private final BatteryStatsManager mBatteryStatsManager; + private final TelephonyUtil mTelephonyUtil; + private final String mTcpBufferSizes; // Used for debug and stats gathering @@ -711,7 +706,8 @@ public class ClientModeImpl extends StateMachine { LinkProbeManager linkProbeManager, BatteryStatsManager batteryStatsManager, SupplicantStateTracker supplicantStateTracker, - MboOceController mboOceController) { + MboOceController mboOceController, + TelephonyUtil telephonyUtil) { super(TAG, looper); mWifiInjector = wifiInjector; mWifiMetrics = mWifiInjector.getWifiMetrics(); @@ -728,6 +724,7 @@ public class ClientModeImpl extends StateMachine { mWifiTrafficPoller = wifiTrafficPoller; mLinkProbeManager = linkProbeManager; mMboOceController = mboOceController; + mTelephonyUtil = telephonyUtil; mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, ""); mBatteryStatsManager = batteryStatsManager; @@ -759,6 +756,7 @@ public class ClientModeImpl extends StateMachine { mNetworkInfo.setIsAvailable(false); mLastBssid = null; mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; + mLastSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; mLastSignalLevel = -1; mCountryCode = countryCode; @@ -1726,6 +1724,7 @@ public class ClientModeImpl extends StateMachine { pw.println("mLastSignalLevel " + mLastSignalLevel); pw.println("mLastBssid " + mLastBssid); pw.println("mLastNetworkId " + mLastNetworkId); + pw.println("mLastSubId " + mLastSubId); pw.println("mOperationalMode " + mOperationalMode); pw.println("mUserWantsSuspendOpt " + mUserWantsSuspendOpt); pw.println("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled); @@ -2597,6 +2596,7 @@ public class ClientModeImpl extends StateMachine { mLastLinkLayerStats = null; registerDisconnected(); mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; + mLastSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; mWifiScoreCard.resetConnectionState(); updateL2KeyAndGroupHint(); } @@ -3294,6 +3294,7 @@ public class ClientModeImpl extends StateMachine { // Initialize data structures mLastBssid = null; mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; + mLastSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; mLastSignalLevel = -1; mWifiInfo.setMacAddress(mWifiNative.getMacAddress(mInterfaceName)); // TODO: b/79504296 This broadcast has been deprecated and should be removed @@ -3635,12 +3636,12 @@ public class ClientModeImpl extends StateMachine { // For SIM & AKA/AKA' EAP method Only, get identity from ICC if (mTargetWifiConfiguration != null && mTargetWifiConfiguration.networkId == netId - && TelephonyUtil.isSimConfig(mTargetWifiConfiguration)) { + && mTargetWifiConfiguration.enterpriseConfig != null + && mTargetWifiConfiguration.enterpriseConfig + .requireSimCredential()) { // Pair<identity, encrypted identity> - Pair<String, String> identityPair = - TelephonyUtil.getSimIdentity(getTelephonyManager(), - new TelephonyUtil(), mTargetWifiConfiguration, - mWifiInjector.getCarrierNetworkConfig()); + Pair<String, String> identityPair = mTelephonyUtil + .getSimIdentity(mTargetWifiConfiguration); Log.i(TAG, "SUP_REQUEST_IDENTITY: identityPair=" + identityPair); if (identityPair != null && identityPair.first != null) { mWifiNative.simIdentityResponse(mInterfaceName, identityPair.first, @@ -3747,12 +3748,12 @@ public class ClientModeImpl extends StateMachine { Log.i(TAG, "Connecting with " + currentMacAddress + " as the mac address"); if (config.enterpriseConfig != null - && TelephonyUtil.isSimEapMethod(config.enterpriseConfig.getEapMethod()) + && config.enterpriseConfig.requireSimCredential() && mWifiInjector.getCarrierNetworkConfig() .isCarrierEncryptionInfoAvailable() && TextUtils.isEmpty(config.enterpriseConfig.getAnonymousIdentity())) { - String anonAtRealm = TelephonyUtil.getAnonymousIdentityWith3GppRealm( - getTelephonyManager()); + String anonAtRealm = mTelephonyUtil + .getAnonymousIdentityWith3GppRealm(config); // Use anonymous@<realm> when pseudonym is not available config.enterpriseConfig.setAnonymousIdentity(anonAtRealm); } @@ -3873,15 +3874,15 @@ public class ClientModeImpl extends StateMachine { // We need to get the updated pseudonym from supplicant for EAP-SIM/AKA/AKA' if (config.enterpriseConfig != null - && TelephonyUtil.isSimEapMethod( - config.enterpriseConfig.getEapMethod())) { + && config.enterpriseConfig.requireSimCredential()) { + mLastSubId = mTelephonyUtil.getBestMatchSubscriptionId(config); String anonymousIdentity = mWifiNative.getEapAnonymousIdentity(mInterfaceName); if (!TextUtils.isEmpty(anonymousIdentity) && !TelephonyUtil .isAnonymousAtRealmIdentity(anonymousIdentity)) { - String decoratedPseudonym = TelephonyUtil - .decoratePseudonymWith3GppRealm(getTelephonyManager(), + String decoratedPseudonym = mTelephonyUtil + .decoratePseudonymWith3GppRealm(config, anonymousIdentity); if (decoratedPseudonym != null) { anonymousIdentity = decoratedPseudonym; @@ -4098,10 +4099,7 @@ public class ClientModeImpl extends StateMachine { case WifiEnterpriseConfig.Eap.AKA: case WifiEnterpriseConfig.Eap.AKA_PRIME: if (errorCode == WifiNative.EAP_SIM_VENDOR_SPECIFIC_CERT_EXPIRED) { - getTelephonyManager() - .createForSubscriptionId( - SubscriptionManager.getDefaultDataSubscriptionId()) - .resetCarrierKeysForImsiEncryption(); + mTelephonyUtil.resetCarrierKeysForImsiEncryption(targetedNetwork); } break; @@ -4527,11 +4525,14 @@ public class ClientModeImpl extends StateMachine { && mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) { WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(mLastNetworkId); - if (TelephonyUtil.isSimConfig(config)) { + if (config.enterpriseConfig != null + && config.enterpriseConfig.requireSimCredential() + && !mTelephonyUtil.isSimPresent(mLastSubId)) { + // check if the removed sim card is associated with current config mWifiMetrics.logStaEvent(StaEvent.TYPE_FRAMEWORK_DISCONNECT, StaEvent.DISCONNECT_RESET_SIM_NETWORKS); - // TODO(b/132385576): STA may immediately connect back to the network - // that we just disconnected from + // TODO(b/132385576): STA may immediately connect back to the + // network that we just disconnected from mWifiNative.disconnect(mInterfaceName); transitionTo(mDisconnectingState); } @@ -5358,8 +5359,8 @@ public class ClientModeImpl extends StateMachine { } void handleGsmAuthRequest(SimAuthRequestData requestData) { - if (mTargetWifiConfiguration == null - || mTargetWifiConfiguration.networkId + if (mTargetWifiConfiguration != null + && mTargetWifiConfiguration.networkId == requestData.networkId) { logd("id matches targetWifiConfiguration"); } else { @@ -5379,16 +5380,16 @@ public class ClientModeImpl extends StateMachine { * 3. 3GPP TS 11.11 2G_authentication [RAND] * [SRES][Cipher Key Kc] */ - String response = - TelephonyUtil.getGsmSimAuthResponse(requestData.data, getTelephonyManager()); + String response = mTelephonyUtil + .getGsmSimAuthResponse(requestData.data, mTargetWifiConfiguration); if (response == null) { // In case of failure, issue may be due to sim type, retry as No.2 case - response = TelephonyUtil.getGsmSimpleSimAuthResponse(requestData.data, - getTelephonyManager()); + response = mTelephonyUtil + .getGsmSimpleSimAuthResponse(requestData.data, mTargetWifiConfiguration); if (response == null) { // In case of failure, issue may be due to sim type, retry as No.3 case - response = TelephonyUtil.getGsmSimpleSimNoLengthAuthResponse(requestData.data, - getTelephonyManager()); + response = mTelephonyUtil.getGsmSimpleSimNoLengthAuthResponse( + requestData.data, mTargetWifiConfiguration); } } if (response == null || response.length() == 0) { @@ -5401,8 +5402,8 @@ public class ClientModeImpl extends StateMachine { } void handle3GAuthRequest(SimAuthRequestData requestData) { - if (mTargetWifiConfiguration == null - || mTargetWifiConfiguration.networkId + if (mTargetWifiConfiguration != null + && mTargetWifiConfiguration.networkId == requestData.networkId) { logd("id matches targetWifiConfiguration"); } else { @@ -5410,8 +5411,8 @@ public class ClientModeImpl extends StateMachine { return; } - SimAuthResponseData response = - TelephonyUtil.get3GAuthResponse(requestData, getTelephonyManager()); + SimAuthResponseData response = mTelephonyUtil + .get3GAuthResponse(requestData, mTargetWifiConfiguration); if (response != null) { mWifiNative.simAuthResponse( mInterfaceName, response.type, response.response); diff --git a/service/java/com/android/server/wifi/SavedNetworkEvaluator.java b/service/java/com/android/server/wifi/SavedNetworkEvaluator.java index f4635ab68..0437dc49a 100644 --- a/service/java/com/android/server/wifi/SavedNetworkEvaluator.java +++ b/service/java/com/android/server/wifi/SavedNetworkEvaluator.java @@ -20,7 +20,6 @@ import android.annotation.NonNull; import android.content.Context; import android.net.wifi.ScanResult; import android.net.wifi.WifiConfiguration; -import android.telephony.SubscriptionManager; import android.util.LocalLog; import com.android.internal.annotations.VisibleForTesting; @@ -39,7 +38,7 @@ public class SavedNetworkEvaluator implements WifiNetworkSelector.NetworkEvaluat private final Clock mClock; private final LocalLog mLocalLog; private final WifiConnectivityHelper mConnectivityHelper; - private final SubscriptionManager mSubscriptionManager; + private final TelephonyUtil mTelephonyUtil; private final int mRssiScoreSlope; private final int mRssiScoreOffset; private final int mSameBssidAward; @@ -59,13 +58,13 @@ public class SavedNetworkEvaluator implements WifiNetworkSelector.NetworkEvaluat SavedNetworkEvaluator(final Context context, ScoringParams scoringParams, WifiConfigManager configManager, Clock clock, LocalLog localLog, WifiConnectivityHelper connectivityHelper, - SubscriptionManager subscriptionManager) { + TelephonyUtil telephonyUtil) { mScoringParams = scoringParams; mWifiConfigManager = configManager; mClock = clock; mLocalLog = localLog; mConnectivityHelper = connectivityHelper; - mSubscriptionManager = subscriptionManager; + mTelephonyUtil = telephonyUtil; mRssiScoreSlope = context.getResources().getInteger( R.integer.config_wifi_framework_RSSI_SCORE_SLOPE); @@ -235,10 +234,15 @@ public class SavedNetworkEvaluator implements WifiNetworkSelector.NetworkEvaluat + " has specified BSSID " + network.BSSID + ". Skip " + scanResult.BSSID); continue; - } else if (TelephonyUtil.isSimConfig(network) - && !TelephonyUtil.isSimPresent(mSubscriptionManager)) { - // Don't select if security type is EAP SIM/AKA/AKA' when SIM is not present. - continue; + } else if (network.enterpriseConfig != null + && network.enterpriseConfig.requireSimCredential()) { + int subId = mTelephonyUtil.getBestMatchSubscriptionId(network); + if (!mTelephonyUtil.isSimPresent(subId)) { + // Don't select if security type is EAP SIM/AKA/AKA' when SIM is not present. + localLog("No SIM card is good for Network " + + WifiNetworkSelector.toNetworkString(network)); + continue; + } } int score = calculateBssidScore(scanResult, network, currentNetwork, currentBssid, diff --git a/service/java/com/android/server/wifi/WifiConfigManager.java b/service/java/com/android/server/wifi/WifiConfigManager.java index 657e05708..958a9f1b0 100644 --- a/service/java/com/android/server/wifi/WifiConfigManager.java +++ b/service/java/com/android/server/wifi/WifiConfigManager.java @@ -41,7 +41,6 @@ import android.os.Process; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; -import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.ArraySet; import android.util.LocalLog; @@ -275,7 +274,6 @@ public class WifiConfigManager { private final Clock mClock; private final UserManager mUserManager; private final BackupManagerProxy mBackupManagerProxy; - private final TelephonyManager mTelephonyManager; private final WifiKeyStore mWifiKeyStore; private final WifiConfigStore mWifiConfigStore; private final WifiPermissionsUtil mWifiPermissionsUtil; @@ -284,6 +282,7 @@ public class WifiConfigManager { private final MacAddressUtil mMacAddressUtil; private boolean mConnectedMacRandomzationSupported; private final Mac mMac; + private final TelephonyUtil mTelephonyUtil; /** * Local log used for debugging any WifiConfigManager issues. @@ -394,7 +393,7 @@ public class WifiConfigManager { */ WifiConfigManager( Context context, Clock clock, UserManager userManager, - TelephonyManager telephonyManager, WifiKeyStore wifiKeyStore, + TelephonyUtil telephonyUtil, WifiKeyStore wifiKeyStore, WifiConfigStore wifiConfigStore, WifiPermissionsUtil wifiPermissionsUtil, WifiPermissionsWrapper wifiPermissionsWrapper, @@ -409,7 +408,7 @@ public class WifiConfigManager { mClock = clock; mUserManager = userManager; mBackupManagerProxy = new BackupManagerProxy(); - mTelephonyManager = telephonyManager; + mTelephonyUtil = telephonyUtil; mWifiKeyStore = wifiKeyStore; mWifiConfigStore = wifiConfigStore; mWifiPermissionsUtil = wifiPermissionsUtil; @@ -1148,6 +1147,7 @@ public class WifiConfigManager { // Copy over macRandomizationSetting internalConfig.macRandomizationSetting = externalConfig.macRandomizationSetting; + internalConfig.carrierId = externalConfig.carrierId; } /** @@ -2978,13 +2978,13 @@ public class WifiConfigManager { public void resetSimNetworks() { if (mVerboseLoggingEnabled) localLog("resetSimNetworks"); for (WifiConfiguration config : getInternalConfiguredNetworks()) { - if (!TelephonyUtil.isSimConfig(config)) { + if (config.enterpriseConfig == null + || !config.enterpriseConfig.requireSimCredential()) { continue; } if (config.enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.PEAP) { - Pair<String, String> currentIdentity = TelephonyUtil.getSimIdentity( - mTelephonyManager, new TelephonyUtil(), config, - mWifiInjector.getCarrierNetworkConfig()); + Pair<String, String> currentIdentity = + mTelephonyUtil.getSimIdentity(config); if (mVerboseLoggingEnabled) { Log.d(TAG, "New identity for config " + config + ": " + currentIdentity); } diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java index 13f6a8267..89151ea3e 100644 --- a/service/java/com/android/server/wifi/WifiInjector.java +++ b/service/java/com/android/server/wifi/WifiInjector.java @@ -56,6 +56,7 @@ import com.android.server.wifi.p2p.WifiP2pMetrics; import com.android.server.wifi.p2p.WifiP2pMonitor; import com.android.server.wifi.p2p.WifiP2pNative; import com.android.server.wifi.rtt.RttMetrics; +import com.android.server.wifi.util.TelephonyUtil; import com.android.server.wifi.util.WifiPermissionsUtil; import com.android.server.wifi.util.WifiPermissionsWrapper; import com.android.server.wifi.wificond.IWificond; @@ -154,6 +155,7 @@ public class WifiInjector { private BssidBlocklistMonitor mBssidBlocklistMonitor; private final MacAddressUtil mMacAddressUtil; private final MboOceController mMboOceController; + private final TelephonyUtil mTelephonyUtil; public WifiInjector(Context context) { if (context == null) { @@ -245,9 +247,10 @@ public class WifiInjector { WifiConfigStore.createSharedFile(mFrameworkFacade.isNiapModeOn(mContext))); SubscriptionManager subscriptionManager = mContext.getSystemService(SubscriptionManager.class); + mTelephonyUtil = new TelephonyUtil(makeTelephonyManager(), subscriptionManager); // Config Manager mWifiConfigManager = new WifiConfigManager(mContext, mClock, - mUserManager, makeTelephonyManager(), + mUserManager, mTelephonyUtil, mWifiKeyStore, mWifiConfigStore, mWifiPermissionsUtil, mWifiPermissionsWrapper, this, new NetworkListSharedStoreData(mContext), new NetworkListUserStoreData(mContext), @@ -270,9 +273,10 @@ public class WifiInjector { mWifiMetrics.setWifiNetworkSelector(mWifiNetworkSelector); mSavedNetworkEvaluator = new SavedNetworkEvaluator(mContext, mScoringParams, mWifiConfigManager, mClock, mConnectivityLocalLog, mWifiConnectivityHelper, - subscriptionManager); + mTelephonyUtil); mWifiNetworkSuggestionsManager = new WifiNetworkSuggestionsManager(mContext, wifiHandler, - this, mWifiPermissionsUtil, mWifiConfigManager, mWifiConfigStore, mWifiMetrics); + this, mWifiPermissionsUtil, mWifiConfigManager, mWifiConfigStore, mWifiMetrics, + mTelephonyUtil); mNetworkSuggestionEvaluator = new NetworkSuggestionEvaluator(mWifiNetworkSuggestionsManager, mWifiConfigManager, mConnectivityLocalLog); mScoredNetworkEvaluator = new ScoredNetworkEvaluator(context, wifiHandler, @@ -313,7 +317,7 @@ public class WifiInjector { this, mBackupManagerProxy, mCountryCode, mWifiNative, new WrongPasswordNotifier(mContext, mFrameworkFacade), mSarManager, mWifiTrafficPoller, mLinkProbeManager, mBatteryStats, - supplicantStateTracker, mMboOceController); + supplicantStateTracker, mMboOceController, mTelephonyUtil); mActiveModeWarden = new ActiveModeWarden(this, wifiLooper, mWifiNative, new DefaultModeManager(mContext), mBatteryStats, mWifiDiagnostics, mContext, mClientModeImpl, mSettingsStore, mFrameworkFacade, mWifiPermissionsUtil); @@ -502,6 +506,10 @@ public class WifiInjector { return (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); } + public TelephonyUtil getTelephonyUtil() { + return mTelephonyUtil; + } + public WifiStateTracker getWifiStateTracker() { return mWifiStateTracker; } diff --git a/service/java/com/android/server/wifi/WifiNetworkSuggestionsManager.java b/service/java/com/android/server/wifi/WifiNetworkSuggestionsManager.java index b94f91da4..0d400c576 100644 --- a/service/java/com/android/server/wifi/WifiNetworkSuggestionsManager.java +++ b/service/java/com/android/server/wifi/WifiNetworkSuggestionsManager.java @@ -52,6 +52,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.internal.notification.SystemNotificationChannels; import com.android.server.wifi.util.ExternalCallbackTracker; +import com.android.server.wifi.util.TelephonyUtil; import com.android.server.wifi.util.WifiPermissionsUtil; import com.android.wifi.R; @@ -113,6 +114,7 @@ public class WifiNetworkSuggestionsManager { private final WifiMetrics mWifiMetrics; private final WifiInjector mWifiInjector; private final FrameworkFacade mFrameworkFacade; + private final TelephonyUtil mTelephonyUtil; /** * Per app meta data to store network suggestions, status, etc for each app providing network @@ -406,7 +408,8 @@ public class WifiNetworkSuggestionsManager { WifiPermissionsUtil wifiPermissionsUtil, WifiConfigManager wifiConfigManager, WifiConfigStore wifiConfigStore, - WifiMetrics wifiMetrics) { + WifiMetrics wifiMetrics, + TelephonyUtil telephonyUtil) { mContext = context; mResources = context.getResources(); mHandler = handler; @@ -419,6 +422,7 @@ public class WifiNetworkSuggestionsManager { mWifiPermissionsUtil = wifiPermissionsUtil; mWifiConfigManager = wifiConfigManager; mWifiMetrics = wifiMetrics; + mTelephonyUtil = telephonyUtil; // register the data store for serializing/deserializing data. wifiConfigStore.registerStoreData( @@ -1000,7 +1004,23 @@ public class WifiNetworkSuggestionsManager { Set<ExtendedWifiNetworkSuggestion> approvedExtNetworkSuggestions = extNetworkSuggestions .stream() - .filter(n -> n.perAppInfo.hasUserApproved) + .filter(n -> { + if (!n.perAppInfo.hasUserApproved) { + return false; + } + WifiConfiguration config = n.wns.wifiConfiguration; + if (config != null && config.enterpriseConfig != null + && config.enterpriseConfig.requireSimCredential()) { + int subId = mTelephonyUtil.getBestMatchSubscriptionId(config); + if (!mTelephonyUtil.isSimPresent(subId)) { + if (mVerboseLoggingEnabled) { + Log.v(TAG, "No SIM is matched, ignore the config."); + } + return false; + } + } + return true; + }) .collect(Collectors.toSet()); // If there is no active notification, check if we need to get approval for any of the apps // & send a notification for one of them. If there are multiple packages awaiting approval, diff --git a/service/java/com/android/server/wifi/util/TelephonyUtil.java b/service/java/com/android/server/wifi/util/TelephonyUtil.java index a80c18cf6..60921725e 100644 --- a/service/java/com/android/server/wifi/util/TelephonyUtil.java +++ b/service/java/com/android/server/wifi/util/TelephonyUtil.java @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiEnterpriseConfig; import android.telephony.ImsiEncryptionInfo; +import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.text.TextUtils; @@ -28,13 +29,14 @@ import android.util.Log; import android.util.Pair; import com.android.internal.annotations.VisibleForTesting; -import com.android.server.wifi.CarrierNetworkConfig; import com.android.server.wifi.WifiNative; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.PublicKey; +import java.util.Arrays; import java.util.HashMap; +import java.util.List; import javax.annotation.Nonnull; import javax.crypto.BadPaddingException; @@ -78,34 +80,83 @@ public class TelephonyUtil { private static final int START_KC_POS = START_SRES_POS + SRES_LEN; private static final int KC_LEN = 8; + private final TelephonyManager mTelephonyManager; + private final SubscriptionManager mSubscriptionManager; + + /** + * Gets the instance of TelephonyUtil. + * @param telephonyManager Instance of {@link TelephonyManager} + * @param subscriptionManager Instance of {@link SubscriptionManager} + * @return The instance of TelephonyUtil + */ + public TelephonyUtil(@NonNull TelephonyManager telephonyManager, + @NonNull SubscriptionManager subscriptionManager) { + mTelephonyManager = telephonyManager; + mSubscriptionManager = subscriptionManager; + } + + /** + * Gets the SubscriptionId of SIM card which is from the carrier specified in config. + * @param config the instance of {@link WifiConfiguration} + * @return the best match SubscriptionId + */ + public int getBestMatchSubscriptionId(WifiConfiguration config) { + List<SubscriptionInfo> subInfoList = mSubscriptionManager.getActiveSubscriptionInfoList(); + if (subInfoList == null || subInfoList.isEmpty()) { + return SubscriptionManager.INVALID_SUBSCRIPTION_ID; + } + // Legacy WifiConfiguration without carrier ID + if (config.carrierId == TelephonyManager.UNKNOWN_CARRIER_ID + && config.enterpriseConfig != null + && config.enterpriseConfig.requireSimCredential()) { + Log.d(TAG, "carrierId is not assigned, using the default data sub."); + return SubscriptionManager.getDefaultDataSubscriptionId(); + } + + int dataSubId = SubscriptionManager.getDefaultDataSubscriptionId(); + int matchSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + for (SubscriptionInfo subInfo : subInfoList) { + if (subInfo.getCarrierId() == config.carrierId) { + matchSubId = subInfo.getSubscriptionId(); + if (matchSubId == dataSubId) { + // Priority of Data sub is higher than non data sub. + break; + } + } + } + Log.d(TAG, "best match subscription id: " + matchSubId); + return matchSubId; + } + + /** + * Check if the specified SIM card is in the device. + * + * @param subId subscription ID of SIM card in the device. + * @return true if the subId is active, otherwise false. + */ + public boolean isSimPresent(int subId) { + return Arrays.stream(mSubscriptionManager.getActiveSubscriptionIdList()) + .anyMatch(id -> id == subId); + } /** * Get the identity for the current SIM or null if the SIM is not available * - * @param tm TelephonyManager instance * @param config WifiConfiguration that indicates what sort of authentication is necessary - * @param telephonyUtil TelephonyUtil instance - * @param carrierNetworkConfig CarrierNetworkConfig instance * @return Pair<identify, encrypted identity> or null if the SIM is not available * or config is invalid */ - public static Pair<String, String> getSimIdentity(TelephonyManager tm, - TelephonyUtil telephonyUtil, - WifiConfiguration config, CarrierNetworkConfig carrierNetworkConfig) { - if (tm == null) { - Log.e(TAG, "No valid TelephonyManager"); - return null; - } - TelephonyManager defaultDataTm = tm.createForSubscriptionId( - SubscriptionManager.getDefaultDataSubscriptionId()); - if (carrierNetworkConfig == null) { - Log.e(TAG, "No valid CarrierNetworkConfig"); + public Pair<String, String> getSimIdentity(WifiConfiguration config) { + int subId = getBestMatchSubscriptionId(config); + if (!SubscriptionManager.isValidSubscriptionId(subId)) { return null; } - String imsi = defaultDataTm.getSubscriberId(); + + TelephonyManager specifiedTm = mTelephonyManager.createForSubscriptionId(subId); + String imsi = specifiedTm.getSubscriberId(); String mccMnc = ""; - if (defaultDataTm.getSimState() == TelephonyManager.SIM_STATE_READY) { - mccMnc = defaultDataTm.getSimOperator(); + if (specifiedTm.getSimState() == TelephonyManager.SIM_STATE_READY) { + mccMnc = specifiedTm.getSimOperator(); } String identity = buildIdentity(getSimMethodForConfig(config), imsi, mccMnc, false); @@ -116,7 +167,7 @@ public class TelephonyUtil { ImsiEncryptionInfo imsiEncryptionInfo; try { - imsiEncryptionInfo = defaultDataTm.getCarrierInfoForImsiEncryption( + imsiEncryptionInfo = specifiedTm.getCarrierInfoForImsiEncryption( TelephonyManager.KEY_TYPE_WLAN); } catch (RuntimeException e) { Log.e(TAG, "Failed to get imsi encryption info: " + e.getMessage()); @@ -127,7 +178,7 @@ public class TelephonyUtil { return Pair.create(identity, ""); } - String encryptedIdentity = buildEncryptedIdentity(telephonyUtil, identity, + String encryptedIdentity = buildEncryptedIdentity(identity, imsiEncryptionInfo); // In case of failure for encryption, abort current EAP authentication. @@ -141,20 +192,17 @@ public class TelephonyUtil { /** * Gets Anonymous identity for current active SIM. * - * @param tm TelephonyManager instance + * @param config the instance of WifiConfiguration. * @return anonymous identity@realm which is based on current MCC/MNC, {@code null} if SIM is * not ready or absent. */ - public static String getAnonymousIdentityWith3GppRealm(@Nonnull TelephonyManager tm) { - if (tm == null) { + public String getAnonymousIdentityWith3GppRealm(@NonNull WifiConfiguration config) { + int subId = getBestMatchSubscriptionId(config); + TelephonyManager specifiedTm = mTelephonyManager.createForSubscriptionId(subId); + if (specifiedTm.getSimState() != TelephonyManager.SIM_STATE_READY) { return null; } - TelephonyManager defaultDataTm = tm.createForSubscriptionId( - SubscriptionManager.getDefaultDataSubscriptionId()); - if (defaultDataTm.getSimState() != TelephonyManager.SIM_STATE_READY) { - return null; - } - String mccMnc = defaultDataTm.getSimOperator(); + String mccMnc = specifiedTm.getSimOperator(); if (mccMnc == null || mccMnc.isEmpty()) { return null; } @@ -176,11 +224,12 @@ public class TelephonyUtil { * a Base64 encoded string. * * @param key The public key to use for encryption + * @param data The data need to be encrypted * @param encodingFlag base64 encoding flag * @return Base64 encoded string, or null if encryption failed */ @VisibleForTesting - public String encryptDataUsingPublicKey(PublicKey key, byte[] data, int encodingFlag) { + public static String encryptDataUsingPublicKey(PublicKey key, byte[] data, int encodingFlag) { try { Cipher cipher = Cipher.getInstance(IMSI_CIPHER_TRANSFORMATION); cipher.init(Cipher.ENCRYPT_MODE, key); @@ -202,13 +251,12 @@ public class TelephonyUtil { * "1" - EAP-SIM Identity * "6" - EAP-AKA' Identity * Encrypted identity format: prefix|IMSI@<NAIRealm> - * @param telephonyUtil TelephonyUtil instance * @param identity permanent identity with format based on section 4.1.1.6 of RFC 4187 * and 4.2.1.6 of RFC 4186. * @param imsiEncryptionInfo The IMSI encryption info retrieved from the SIM * @return "\0" + encryptedIdentity + "{, Key Identifier AVP}" */ - private static String buildEncryptedIdentity(TelephonyUtil telephonyUtil, String identity, + private static String buildEncryptedIdentity(String identity, ImsiEncryptionInfo imsiEncryptionInfo) { if (imsiEncryptionInfo == null) { Log.e(TAG, "imsiEncryptionInfo is not valid"); @@ -220,7 +268,7 @@ public class TelephonyUtil { } // Build and return the encrypted identity. - String encryptedIdentity = telephonyUtil.encryptDataUsingPublicKey( + String encryptedIdentity = encryptDataUsingPublicKey( imsiEncryptionInfo.getPublicKey(), identity.getBytes(), Base64.NO_WRAP); if (encryptedIdentity == null) { Log.e(TAG, "Failed to encrypt IMSI"); @@ -324,16 +372,6 @@ public class TelephonyUtil { } /** - * Checks if the network is a SIM config. - * - * @param config Config corresponding to the network. - * @return true if it is a SIM config, false otherwise. - */ - public static boolean isSimConfig(WifiConfiguration config) { - return getSimMethodForConfig(config) != WifiEnterpriseConfig.Eap.NONE; - } - - /** * Returns true if {@code identity} contains an anonymous@realm identity, false otherwise. */ public static boolean isAnonymousAtRealmIdentity(String identity) { @@ -448,12 +486,12 @@ public class TelephonyUtil { * [Length][RES][Length][CK][Length][IK] and more * * @param requestData RAND data from server. - * @param tm the instance of TelephonyManager. + * @param config The instance of WifiConfiguration. * @return the response data processed by SIM. If all request data is malformed, then returns * empty string. If request data is invalid, then returns null. */ - public static String getGsmSimAuthResponse(String[] requestData, TelephonyManager tm) { - return getGsmAuthResponseWithLength(requestData, tm, TelephonyManager.APPTYPE_USIM); + public String getGsmSimAuthResponse(String[] requestData, WifiConfiguration config) { + return getGsmAuthResponseWithLength(requestData, config, TelephonyManager.APPTYPE_USIM); } /** @@ -465,22 +503,22 @@ public class TelephonyUtil { * [Length][SRES][Length][Cipher Key Kc] * * @param requestData RAND data from server. - * @param tm the instance of TelephonyManager. + * @param config The instance of WifiConfiguration. * @return the response data processed by SIM. If all request data is malformed, then returns * empty string. If request data is invalid, then returns null. */ - public static String getGsmSimpleSimAuthResponse(String[] requestData, TelephonyManager tm) { - return getGsmAuthResponseWithLength(requestData, tm, TelephonyManager.APPTYPE_SIM); + public String getGsmSimpleSimAuthResponse(String[] requestData, + WifiConfiguration config) { + return getGsmAuthResponseWithLength(requestData, config, TelephonyManager.APPTYPE_SIM); } - private static String getGsmAuthResponseWithLength(String[] requestData, TelephonyManager tm, - int appType) { - if (tm == null) { - Log.e(TAG, "No valid TelephonyManager"); + private String getGsmAuthResponseWithLength(String[] requestData, + WifiConfiguration config, int appType) { + int subId = getBestMatchSubscriptionId(config); + if (!SubscriptionManager.isValidSubscriptionId(subId)) { return null; } - TelephonyManager defaultDataTm = tm.createForSubscriptionId( - SubscriptionManager.getDefaultDataSubscriptionId()); + StringBuilder sb = new StringBuilder(); for (String challenge : requestData) { if (challenge == null || challenge.isEmpty()) { @@ -497,8 +535,8 @@ public class TelephonyUtil { } String base64Challenge = Base64.encodeToString(rand, Base64.NO_WRAP); - - String tmResponse = defaultDataTm.getIccAuthentication( + TelephonyManager specifiedTm = mTelephonyManager.createForSubscriptionId(subId); + String tmResponse = specifiedTm.getIccAuthentication( appType, TelephonyManager.AUTHTYPE_EAP_SIM, base64Challenge); Log.v(TAG, "Raw Response - " + tmResponse); @@ -542,18 +580,18 @@ public class TelephonyUtil { * [SRES][Cipher Key Kc] * * @param requestData RAND data from server. - * @param tm the instance of TelephonyManager. + * @param config the instance of WifiConfiguration. * @return the response data processed by SIM. If all request data is malformed, then returns * empty string. If request data is invalid, then returns null. */ - public static String getGsmSimpleSimNoLengthAuthResponse(String[] requestData, - TelephonyManager tm) { - if (tm == null) { - Log.e(TAG, "No valid TelephonyManager"); + public String getGsmSimpleSimNoLengthAuthResponse(String[] requestData, + @NonNull WifiConfiguration config) { + + int subId = getBestMatchSubscriptionId(config); + if (!SubscriptionManager.isValidSubscriptionId(subId)) { return null; } - TelephonyManager defaultDataTm = tm.createForSubscriptionId( - SubscriptionManager.getDefaultDataSubscriptionId()); + StringBuilder sb = new StringBuilder(); for (String challenge : requestData) { if (challenge == null || challenge.isEmpty()) { @@ -570,8 +608,8 @@ public class TelephonyUtil { } String base64Challenge = Base64.encodeToString(rand, Base64.NO_WRAP); - - String tmResponse = defaultDataTm.getIccAuthentication(TelephonyManager.APPTYPE_SIM, + TelephonyManager specifiedTm = mTelephonyManager.createForSubscriptionId(subId); + String tmResponse = specifiedTm.getIccAuthentication(TelephonyManager.APPTYPE_SIM, TelephonyManager.AUTHTYPE_EAP_SIM, base64Challenge); Log.v(TAG, "Raw Response - " + tmResponse); @@ -628,8 +666,15 @@ public class TelephonyUtil { public String response; } - public static SimAuthResponseData get3GAuthResponse(SimAuthRequestData requestData, - TelephonyManager tm) { + /** + * Get the response data for 3G authentication. + * + * @param requestData authentication request data from server. + * @param config the instance of WifiConfiguration. + * @return the response data processed by SIM. If request data is invalid, then returns null. + */ + public SimAuthResponseData get3GAuthResponse(SimAuthRequestData requestData, + WifiConfiguration config) { StringBuilder sb = new StringBuilder(); byte[] rand = null; byte[] authn = null; @@ -649,15 +694,15 @@ public class TelephonyUtil { String tmResponse = ""; if (rand != null && authn != null) { String base64Challenge = Base64.encodeToString(concatHex(rand, authn), Base64.NO_WRAP); - if (tm != null) { - tmResponse = tm - .createForSubscriptionId(SubscriptionManager.getDefaultDataSubscriptionId()) - .getIccAuthentication(TelephonyManager.APPTYPE_USIM, - TelephonyManager.AUTHTYPE_EAP_AKA, base64Challenge); - Log.v(TAG, "Raw Response - " + tmResponse); - } else { - Log.e(TAG, "No valid TelephonyManager"); + int subId = getBestMatchSubscriptionId(config); + if (!SubscriptionManager.isValidSubscriptionId(subId)) { + return null; } + tmResponse = mTelephonyManager + .createForSubscriptionId(subId) + .getIccAuthentication(TelephonyManager.APPTYPE_USIM, + TelephonyManager.AUTHTYPE_EAP_AKA, base64Challenge); + Log.v(TAG, "Raw Response - " + tmResponse); } boolean goodReponse = false; @@ -735,26 +780,27 @@ public class TelephonyUtil { /** * Decorates a pseudonym with the NAI realm, in case it wasn't provided by the server * - * @param tm TelephonyManager instance + * @param config The instance of WifiConfiguration * @param pseudonym The pseudonym (temporary identity) provided by the server * @return pseudonym@realm which is based on current MCC/MNC, {@code null} if SIM is * not ready or absent. */ - public static String decoratePseudonymWith3GppRealm(@NonNull TelephonyManager tm, + public String decoratePseudonymWith3GppRealm(@NonNull WifiConfiguration config, String pseudonym) { - if (tm == null || TextUtils.isEmpty(pseudonym)) { + if (TextUtils.isEmpty(pseudonym)) { return null; } if (pseudonym.contains("@")) { // Pseudonym is already decorated return pseudonym; } - TelephonyManager defaultDataTm = tm.createForSubscriptionId( - SubscriptionManager.getDefaultDataSubscriptionId()); - if (defaultDataTm.getSimState() != TelephonyManager.SIM_STATE_READY) { + int subId = getBestMatchSubscriptionId(config); + + TelephonyManager specifiedTm = mTelephonyManager.createForSubscriptionId(subId); + if (specifiedTm.getSimState() != TelephonyManager.SIM_STATE_READY) { return null; } - String mccMnc = defaultDataTm.getSimOperator(); + String mccMnc = specifiedTm.getSimOperator(); if (mccMnc == null || mccMnc.isEmpty()) { return null; } @@ -770,4 +816,17 @@ public class TelephonyUtil { String realm = String.format(THREE_GPP_NAI_REALM_FORMAT, mnc, mcc); return String.format("%s@%s", pseudonym, realm); } + + /** + * Reset the downloaded IMSI encryption key. + * @param config Instance of WifiConfiguration + */ + public void resetCarrierKeysForImsiEncryption(@NonNull WifiConfiguration config) { + int subId = getBestMatchSubscriptionId(config); + if (!SubscriptionManager.isValidSubscriptionId(subId)) { + return; + } + TelephonyManager specifiedTm = mTelephonyManager.createForSubscriptionId(subId); + specifiedTm.resetCarrierKeysForImsiEncryption(); + } } |