diff options
-rw-r--r-- | Android.bp | 1 | ||||
-rw-r--r-- | OWNERS | 2 | ||||
-rw-r--r-- | flags/Android.bp | 5 | ||||
-rw-r--r-- | flags/main.aconfig | 19 | ||||
-rw-r--r-- | src/com/google/android/iwlan/IwlanCarrierConfig.java | 93 | ||||
-rw-r--r-- | src/com/google/android/iwlan/IwlanDataService.java | 50 | ||||
-rw-r--r-- | src/com/google/android/iwlan/IwlanEventListener.java | 4 | ||||
-rw-r--r-- | src/com/google/android/iwlan/epdg/EpdgChildSaProposal.java | 79 | ||||
-rw-r--r-- | src/com/google/android/iwlan/epdg/EpdgIkeSaProposal.java | 117 | ||||
-rw-r--r-- | src/com/google/android/iwlan/epdg/EpdgSaProposal.java | 329 | ||||
-rw-r--r-- | src/com/google/android/iwlan/epdg/EpdgSelector.java | 7 | ||||
-rw-r--r-- | src/com/google/android/iwlan/epdg/EpdgTunnelManager.java | 323 | ||||
-rw-r--r-- | test/com/google/android/iwlan/IwlanDataServiceTest.java | 108 | ||||
-rw-r--r-- | test/com/google/android/iwlan/IwlanEventListenerTest.java | 4 | ||||
-rw-r--r-- | test/com/google/android/iwlan/epdg/EpdgTunnelManagerTest.java | 218 |
15 files changed, 1255 insertions, 104 deletions
@@ -30,6 +30,7 @@ android_app { libs: [ "android.net.ipsec.ike.stubs.system", + "androidx.annotation_annotation", "auto_value_annotations", "framework-annotations-lib", "framework-connectivity", @@ -1,5 +1,5 @@ -edensu@google.com amreddy@google.com radhikaagrawal@google.com pochunlee@google.com apsankar@google.com +tairuw@google.com diff --git a/flags/Android.bp b/flags/Android.bp index 28aa750..f3e0c76 100644 --- a/flags/Android.bp +++ b/flags/Android.bp @@ -21,12 +21,13 @@ package { aconfig_declarations { name: "iwlan_telephony_flags", package: "com.google.android.iwlan.flags", + container: "system", srcs: [ - "main.aconfig", + "main.aconfig", ], } java_aconfig_library { name: "iwlan_telephony_flags_lib", - aconfig_declarations: "iwlan_telephony_flags" + aconfig_declarations: "iwlan_telephony_flags", } diff --git a/flags/main.aconfig b/flags/main.aconfig index 9bc80a1..57b0527 100644 --- a/flags/main.aconfig +++ b/flags/main.aconfig @@ -1,4 +1,5 @@ package: "com.google.android.iwlan.flags" +container: "system" flag { name: "prevent_epdg_selection_threads_exhausted" @@ -7,6 +8,24 @@ flag { bug: "278788983" } flag { + name: "aead_algos_enabled" + namespace: "iwlan_telephony" + description: "Add AES_GCM algorithm support in IWLAN." + bug: "306119890" +} +flag { + name: "multiple_sa_proposals" + namespace: "iwlan_telephony" + description: "Add multiple proposals of IKE SA and Child SA" + bug: "287296642" +} +flag { + name: "high_secure_transforms_prioritized" + namespace: "iwlan_telephony" + description: "Reorder IKE and Child SA security transforms with high secured as prioritized" + bug: "306323917" +} +flag { name: "epdg_selection_exclude_failed_ip_address" namespace: "iwlan_telephony" description: "Exclude the failed ip address in epdg selection until tunnel establish successfully or all ip address candidates are failed" diff --git a/src/com/google/android/iwlan/IwlanCarrierConfig.java b/src/com/google/android/iwlan/IwlanCarrierConfig.java index bb3a20f..e68341a 100644 --- a/src/com/google/android/iwlan/IwlanCarrierConfig.java +++ b/src/com/google/android/iwlan/IwlanCarrierConfig.java @@ -21,6 +21,8 @@ import android.os.PersistableBundle; import android.support.annotation.NonNull; import android.telephony.CarrierConfigManager; +import androidx.annotation.VisibleForTesting; + /** Class for handling IWLAN carrier configuration. */ public class IwlanCarrierConfig { static final String PREFIX = "iwlan."; @@ -42,6 +44,13 @@ public class IwlanCarrierConfig { PREFIX + "n1_mode_exclusion_for_emergency_session"; /** + * Key to decide whether N1 mode shall be enabled or disabled depending on 5G enabling status + * via the UI/UX. See {@link #DEFAULT_UPDATE_N1_MODE_ON_UI_CHANGE_BOOL} for the default value. + */ + public static final String KEY_UPDATE_N1_MODE_ON_UI_CHANGE_BOOL = + PREFIX + "update_n1_mode_on_ui_change_bool"; + + /** * Default delay in seconds for releasing the IWLAN connection after a WWAN handover. This is * the default value for {@link #KEY_HANDOVER_TO_WWAN_RELEASE_DELAY_SECOND_INT}. */ @@ -53,10 +62,18 @@ public class IwlanCarrierConfig { */ public static final boolean DEFAULT_N1_MODE_EXCLUSION_FOR_EMERGENCY_SESSION_BOOL = false; - private static PersistableBundle mHiddenBundle = new PersistableBundle(); + /** + * The default value for determining whether N1 mode shall be enabled or disabled depending on + * 5G enabling status via the UI/UX. + */ + public static final boolean DEFAULT_UPDATE_N1_MODE_ON_UI_CHANGE_BOOL = true; + + private static PersistableBundle sTestBundle = new PersistableBundle(); + + private static PersistableBundle sHiddenBundle = new PersistableBundle(); static { - mHiddenBundle = createHiddenDefaultConfig(); + sHiddenBundle = createHiddenDefaultConfig(); } /** @@ -72,6 +89,8 @@ public class IwlanCarrierConfig { bundle.putBoolean( KEY_N1_MODE_EXCLUSION_FOR_EMERGENCY_SESSION_BOOL, DEFAULT_N1_MODE_EXCLUSION_FOR_EMERGENCY_SESSION_BOOL); + bundle.putBoolean( + KEY_UPDATE_N1_MODE_ON_UI_CHANGE_BOOL, DEFAULT_UPDATE_N1_MODE_ON_UI_CHANGE_BOOL); return bundle; } @@ -88,13 +107,17 @@ public class IwlanCarrierConfig { } private static PersistableBundle getDefaultConfig(String key) { + if (sTestBundle.containsKey(key)) { + return sTestBundle; + } + PersistableBundle bundle = CarrierConfigManager.getDefaultConfig(); if (bundle.containsKey(key)) { return bundle; } - if (mHiddenBundle.containsKey(key)) { - return mHiddenBundle; + if (sHiddenBundle.containsKey(key)) { + return sHiddenBundle; } throw new IllegalArgumentException("Default config not found for key: " + key); @@ -274,6 +297,7 @@ public class IwlanCarrierConfig { public static boolean getDefaultConfigBoolean(String key) { return getDefaultConfig(key).getBoolean(key); } + /** * Gets the default configuration int[] value for a given key. * @@ -295,6 +319,7 @@ public class IwlanCarrierConfig { public static long[] getDefaultConfigLongArray(String key) { return getDefaultConfig(key).getLongArray(key); } + /** * Gets the default configuration double[] value for a given key. * @@ -327,4 +352,64 @@ public class IwlanCarrierConfig { public static boolean[] getDefaultConfigBooleanArray(String key) { return getDefaultConfig(key).getBooleanArray(key); } + + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + static void putTestConfigBundle(PersistableBundle bundle) { + sTestBundle.putAll(bundle); + } + + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + static void putTestConfigInt(@NonNull String key, int value) { + sTestBundle.putInt(key, value); + } + + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + static void putTestConfigLong(@NonNull String key, long value) { + sTestBundle.putLong(key, value); + } + + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + static void putTestConfigDouble(@NonNull String key, double value) { + sTestBundle.putDouble(key, value); + } + + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + static void putTestConfigBoolean(@NonNull String key, boolean value) { + sTestBundle.putBoolean(key, value); + } + + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + static void putTestConfigString(@NonNull String key, String value) { + sTestBundle.putString(key, value); + } + + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + static void putTestConfigIntArray(@NonNull String key, @NonNull int[] value) { + sTestBundle.putIntArray(key, value); + } + + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + static void putTestConfigLongArray(@NonNull String key, @NonNull long[] value) { + sTestBundle.putLongArray(key, value); + } + + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + static void putTestConfigDoubleArray(@NonNull String key, @NonNull double[] value) { + sTestBundle.putDoubleArray(key, value); + } + + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + static void putTestConfigBooleanArray(@NonNull String key, @NonNull boolean[] value) { + sTestBundle.putBooleanArray(key, value); + } + + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + static void putTestConfigStringArray(@NonNull String key, @NonNull String[] value) { + sTestBundle.putStringArray(key, value); + } + + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + static void resetTestConfig() { + sTestBundle.clear(); + } } diff --git a/src/com/google/android/iwlan/IwlanDataService.java b/src/com/google/android/iwlan/IwlanDataService.java index 2bf967a..7c680ea 100644 --- a/src/com/google/android/iwlan/IwlanDataService.java +++ b/src/com/google/android/iwlan/IwlanDataService.java @@ -20,6 +20,11 @@ import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.ipsec.ike.ike3gpp.Ike3gppParams.PDU_SESSION_ID_UNSET; +import static com.google.android.iwlan.epdg.EpdgTunnelManager.BRINGDOWN_REASON_DEACTIVATE_DATA_CALL; +import static com.google.android.iwlan.epdg.EpdgTunnelManager.BRINGDOWN_REASON_IN_DEACTIVATING_STATE; +import static com.google.android.iwlan.epdg.EpdgTunnelManager.BRINGDOWN_REASON_NETWORK_UPDATE_WHEN_TUNNEL_IN_BRINGUP; +import static com.google.android.iwlan.epdg.EpdgTunnelManager.BRINGDOWN_REASON_SERVICE_OUT_OF_SYNC; + import android.content.Context; import android.content.Intent; import android.net.ConnectivityManager; @@ -923,7 +928,8 @@ public class IwlanDataService extends DataService { entry.getKey(), true /* forceClose */, getIwlanTunnelCallback(), - getIwlanTunnelMetrics()); + getIwlanTunnelMetrics(), + BRINGDOWN_REASON_IN_DEACTIVATING_STATE); } } } @@ -1047,7 +1053,8 @@ public class IwlanDataService extends DataService { entry.getKey(), true /* forceClose */, getIwlanTunnelCallback(), - getIwlanTunnelMetrics()); + getIwlanTunnelMetrics(), + BRINGDOWN_REASON_NETWORK_UPDATE_WHEN_TUNNEL_IN_BRINGUP); } } } @@ -1229,7 +1236,10 @@ public class IwlanDataService extends DataService { // TODO(b/309867756): Include N1_MODE_CAPABILITY inclusion status in metrics. private boolean needIncludeN1ModeCapability() { - if (!mFeatureFlags.updateN1ModeOnUiChange()) { + if (!IwlanCarrierConfig.getConfigBoolean( + mContext, + getSlotIndex(), + IwlanCarrierConfig.KEY_UPDATE_N1_MODE_ON_UI_CHANGE_BOOL)) { return isN1ModeSupported(); } if (!isN1ModeSupported()) { @@ -1247,10 +1257,10 @@ public class IwlanDataService extends DataService { protected boolean isN1ModeSupported() { int[] nrAvailabilities = - IwlanHelper.getConfig( - CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY, + IwlanCarrierConfig.getConfigIntArray( mContext, - getSlotIndex()); + getSlotIndex(), + CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY); Log.d( TAG, "KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY : " @@ -1508,11 +1518,11 @@ public class IwlanDataService extends DataService { if (cellInfolist != null && iwlanDataServiceProvider.isRegisteredCellInfoChanged(cellInfolist)) { int[] addrResolutionMethods = - IwlanHelper.getConfig( - CarrierConfigManager.Iwlan - .KEY_EPDG_ADDRESS_PRIORITY_INT_ARRAY, + IwlanCarrierConfig.getConfigIntArray( mContext, - iwlanDataServiceProvider.getSlotIndex()); + iwlanDataServiceProvider.getSlotIndex(), + CarrierConfigManager.Iwlan + .KEY_EPDG_ADDRESS_PRIORITY_INT_ARRAY); for (int addrResolutionMethod : addrResolutionMethods) { if (addrResolutionMethod == CarrierConfigManager.Iwlan.EPDG_ADDRESS_CELLULAR_LOC) { @@ -1529,7 +1539,10 @@ public class IwlanDataService extends DataService { int previousCallState = iwlanDataServiceProvider.mCallState; int currentCallState = iwlanDataServiceProvider.mCallState = msg.arg2; - if (!mFeatureFlags.updateN1ModeOnUiChange()) { + if (!IwlanCarrierConfig.getConfigBoolean( + mContext, + iwlanDataServiceProvider.getSlotIndex(), + IwlanCarrierConfig.KEY_UPDATE_N1_MODE_ON_UI_CHANGE_BOOL)) { break; } @@ -1542,11 +1555,14 @@ public class IwlanDataService extends DataService { break; case IwlanEventListener.PREFERRED_NETWORK_TYPE_CHANGED_EVENT: - if (!mFeatureFlags.updateN1ModeOnUiChange()) { - break; - } iwlanDataServiceProvider = (IwlanDataServiceProvider) getDataServiceProvider(msg.arg1); + if (!IwlanCarrierConfig.getConfigBoolean( + mContext, + iwlanDataServiceProvider.getSlotIndex(), + IwlanCarrierConfig.KEY_UPDATE_N1_MODE_ON_UI_CHANGE_BOOL)) { + break; + } long allowedNetworkType = (long) msg.obj; onPreferredNetworkTypeChanged(iwlanDataServiceProvider, allowedNetworkType); break; @@ -1642,7 +1658,8 @@ public class IwlanDataService extends DataService { dataProfile.getApnSetting().getApnName(), true /* forceClose */, iwlanDataServiceProvider.getIwlanTunnelCallback(), - iwlanDataServiceProvider.getIwlanTunnelMetrics()); + iwlanDataServiceProvider.getIwlanTunnelMetrics(), + BRINGDOWN_REASON_SERVICE_OUT_OF_SYNC); iwlanDataServiceProvider.deliverCallback( IwlanDataServiceProvider.CALLBACK_TYPE_SETUP_DATACALL_COMPLETE, 5 /* DataServiceCallback @@ -1913,7 +1930,8 @@ public class IwlanDataService extends DataService { matchingApn, isNetworkLost || isHandoverSuccessful, /* forceClose */ serviceProvider.getIwlanTunnelCallback(), - serviceProvider.getIwlanTunnelMetrics()); + serviceProvider.getIwlanTunnelMetrics(), + BRINGDOWN_REASON_DEACTIVATE_DATA_CALL); } private void resumePendingDeactivationIfExists( diff --git a/src/com/google/android/iwlan/IwlanEventListener.java b/src/com/google/android/iwlan/IwlanEventListener.java index 890afb4..427f4a7 100644 --- a/src/com/google/android/iwlan/IwlanEventListener.java +++ b/src/com/google/android/iwlan/IwlanEventListener.java @@ -187,10 +187,6 @@ public class IwlanEventListener { public void onAllowedNetworkTypesChanged( @TelephonyManager.AllowedNetworkTypesReason int reason, @TelephonyManager.NetworkTypeBitMask long allowedNetworkType) { - if (!mFeatureFlags.updateN1ModeOnUiChange()) { - return; - } - if (reason != TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER) { return; } diff --git a/src/com/google/android/iwlan/epdg/EpdgChildSaProposal.java b/src/com/google/android/iwlan/epdg/EpdgChildSaProposal.java new file mode 100644 index 0000000..d85e322 --- /dev/null +++ b/src/com/google/android/iwlan/epdg/EpdgChildSaProposal.java @@ -0,0 +1,79 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.iwlan.epdg; + +import android.net.ipsec.ike.ChildSaProposal; +import android.util.Pair; + +public class EpdgChildSaProposal extends EpdgSaProposal { + /** + * Builds {@link ChildSaProposal} of carrier proposed encryption algorithms (non-AEAD) cipher + * suit. + */ + public ChildSaProposal buildProposedChildSaProposal() { + return buildProposal(false, true); + } + + /** Builds {@link ChildSaProposal} of carrier proposed AEAD algorithms cipher suit. */ + public ChildSaProposal buildProposedChildSaAeadProposal() { + return buildProposal(true, true); + } + + /** + * Builds {@link ChildSaProposal} of Iwlan supported encryption algorithms (non-AEAD) cipher + * suit. + */ + public ChildSaProposal buildSupportedChildSaProposal() { + return buildProposal(false, false); + } + + /** Builds {@link ChildSaProposal} of Iwlan supported AEAD algorithms cipher suit. */ + public ChildSaProposal buildSupportedChildSaAeadProposal() { + return buildProposal(true, false); + } + + private ChildSaProposal buildProposal(boolean isAead, boolean isProposed) { + ChildSaProposal.Builder saProposalBuilder = new ChildSaProposal.Builder(); + + int[] dhGroups = getDhGroups(); + for (int dhGroup : dhGroups) { + saProposalBuilder.addDhGroup(dhGroup); + } + + Pair<Integer, Integer>[] encrAlgos; + + if (isAead) { + encrAlgos = (isProposed) ? getAeadAlgos() : getSupportedAeadAlgos(); + } else { + encrAlgos = (isProposed) ? getEncryptionAlgos() : getSupportedEncryptionAlgos(); + } + + for (Pair<Integer, Integer> encrAlgo : encrAlgos) { + saProposalBuilder.addEncryptionAlgorithm(encrAlgo.first, encrAlgo.second); + } + + if (!isAead) { + int[] integrityAlgos = + (isProposed) ? getIntegrityAlgos() : getSupportedIntegrityAlgos(); + for (int integrityAlgo : integrityAlgos) { + saProposalBuilder.addIntegrityAlgorithm(integrityAlgo); + } + } + + return saProposalBuilder.build(); + } +} diff --git a/src/com/google/android/iwlan/epdg/EpdgIkeSaProposal.java b/src/com/google/android/iwlan/epdg/EpdgIkeSaProposal.java new file mode 100644 index 0000000..f4d6d56 --- /dev/null +++ b/src/com/google/android/iwlan/epdg/EpdgIkeSaProposal.java @@ -0,0 +1,117 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.iwlan.epdg; + +import android.net.ipsec.ike.IkeSaProposal; +import android.util.Pair; + +import java.util.LinkedHashSet; + +public class EpdgIkeSaProposal extends EpdgSaProposal { + protected final LinkedHashSet<Integer> mProposedPrfAlgos = new LinkedHashSet<>(); + + /** + * Add proposed PRF algorithms by the carrier. + * + * @param prfAlgos proposed PRF algorithms + */ + public void addProposedPrfAlgorithm(int[] prfAlgos) { + for (int prfAlgo : prfAlgos) { + if (validateConfig(prfAlgo, VALID_PRF_ALGOS, CONFIG_TYPE_PRF_ALGO)) { + mProposedPrfAlgos.add(prfAlgo); + } + } + } + + private int[] getPrfAlgos() { + if (isSaferProposalsPrioritized()) { + return mProposedPrfAlgos.stream() + .sorted( + (item1, item2) -> + compareTransformPriority(VALID_PRF_ALGOS, item1, item2)) + .mapToInt(Integer::intValue) + .toArray(); + } + + return mProposedPrfAlgos.stream().mapToInt(Integer::intValue).toArray(); + } + + private int[] getSupportedPrfAlgos() { + return VALID_PRF_ALGOS.stream().mapToInt(Integer::intValue).toArray(); + } + + /** + * Builds {@link IkeSaProposal} of carrier proposed encryption algorithms (non-AEAD) cipher + * suit. + */ + public IkeSaProposal buildProposedIkeSaProposal() { + return buildProposal(false, true); + } + + /** Builds {@link IkeSaProposal} of carrier proposed AEAD algorithms cipher suit. */ + public IkeSaProposal buildProposedIkeSaAeadProposal() { + return buildProposal(true, true); + } + + /** + * Builds {@link IkeSaProposal} of Iwlan supported encryption algorithms (non-AEAD) cipher suit. + */ + public IkeSaProposal buildSupportedIkeSaProposal() { + return buildProposal(false, false); + } + + /** Builds {@link IkeSaProposal} of Iwlan supported AEAD algorithms cipher suit. */ + public IkeSaProposal buildSupportedIkeSaAeadProposal() { + return buildProposal(true, false); + } + + private IkeSaProposal buildProposal(boolean isAead, boolean isProposed) { + IkeSaProposal.Builder saProposalBuilder = new IkeSaProposal.Builder(); + + int[] dhGroups = isProposed ? getDhGroups() : getSupportedDhGroups(); + for (int dhGroup : dhGroups) { + saProposalBuilder.addDhGroup(dhGroup); + } + + Pair<Integer, Integer>[] encrAlgos; + + if (isAead) { + encrAlgos = (isProposed) ? getAeadAlgos() : getSupportedAeadAlgos(); + } else { + encrAlgos = (isProposed) ? getEncryptionAlgos() : getSupportedEncryptionAlgos(); + } + + for (Pair<Integer, Integer> encrAlgo : encrAlgos) { + saProposalBuilder.addEncryptionAlgorithm(encrAlgo.first, encrAlgo.second); + } + + if (!isAead) { + int[] integrityAlgos = + (isProposed) ? getIntegrityAlgos() : getSupportedIntegrityAlgos(); + for (int integrityAlgo : integrityAlgos) { + saProposalBuilder.addIntegrityAlgorithm(integrityAlgo); + } + } + + int[] prfAlgos = (isProposed) ? getPrfAlgos() : getSupportedPrfAlgos(); + for (int prfAlgo : prfAlgos) { + saProposalBuilder.addPseudorandomFunction(prfAlgo); + } + + return saProposalBuilder.build(); + } +} diff --git a/src/com/google/android/iwlan/epdg/EpdgSaProposal.java b/src/com/google/android/iwlan/epdg/EpdgSaProposal.java new file mode 100644 index 0000000..871cc5c --- /dev/null +++ b/src/com/google/android/iwlan/epdg/EpdgSaProposal.java @@ -0,0 +1,329 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.iwlan.epdg; + +import android.net.ipsec.ike.SaProposal; +import android.util.Log; +import android.util.Pair; + +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +abstract class EpdgSaProposal { + private static final String TAG = EpdgSaProposal.class.getSimpleName(); + private static final Set<Integer> VALID_DH_GROUPS; + private static final Set<Integer> VALID_KEY_LENGTHS; + protected static final Set<Integer> VALID_PRF_ALGOS; + private static final Set<Integer> VALID_INTEGRITY_ALGOS; + private static final Set<Integer> VALID_ENCRYPTION_ALGOS; + private static final Set<Integer> VALID_AEAD_ALGOS; + + private static final String CONFIG_TYPE_DH_GROUP = "dh group"; + private static final String CONFIG_TYPE_KEY_LEN = "algorithm key length"; + protected static final String CONFIG_TYPE_PRF_ALGO = "prf algorithm"; + private static final String CONFIG_TYPE_INTEGRITY_ALGO = "integrity algorithm"; + private static final String CONFIG_TYPE_ENCRYPT_ALGO = "encryption algorithm"; + private static final String CONFIG_TYPE_AEAD_ALGO = "AEAD algorithm"; + + private boolean mSaferAlgosPrioritized = false; + + /* + * Each transform below filled with high secured order and index of each value + * represents the priority. + * Safer transform has high priority and proposals will be orders based on + * the priority order. + * For example, DH Group 4096 has more priority compare to 3072, and 3072 + * has more priority than 2048. + * With reference to 3GPP TS 33.210 and RFC 8221, high secured transforms + * are prioritized in IKE and CHILD SA proposals. + */ + static { + VALID_DH_GROUPS = + Collections.unmodifiableSet( + new LinkedHashSet<Integer>( + List.of( + SaProposal.DH_GROUP_4096_BIT_MODP, + SaProposal.DH_GROUP_3072_BIT_MODP, + SaProposal.DH_GROUP_2048_BIT_MODP, + SaProposal.DH_GROUP_1536_BIT_MODP, + SaProposal.DH_GROUP_1024_BIT_MODP))); + + VALID_KEY_LENGTHS = + Collections.unmodifiableSet( + new LinkedHashSet<Integer>( + List.of( + SaProposal.KEY_LEN_AES_256, + SaProposal.KEY_LEN_AES_192, + SaProposal.KEY_LEN_AES_128))); + + VALID_ENCRYPTION_ALGOS = + Collections.unmodifiableSet( + new LinkedHashSet<Integer>( + List.of( + SaProposal.ENCRYPTION_ALGORITHM_AES_CBC, + SaProposal.ENCRYPTION_ALGORITHM_AES_CTR))); + + VALID_INTEGRITY_ALGOS = + Collections.unmodifiableSet( + new LinkedHashSet<Integer>( + List.of( + SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_512_256, + SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_384_192, + SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128, + SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96, + SaProposal.INTEGRITY_ALGORITHM_AES_XCBC_96))); + + VALID_AEAD_ALGOS = + Collections.unmodifiableSet( + new LinkedHashSet<Integer>( + List.of( + SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16, + SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12, + SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8))); + + VALID_PRF_ALGOS = + Collections.unmodifiableSet( + new LinkedHashSet<Integer>( + List.of( + SaProposal.PSEUDORANDOM_FUNCTION_SHA2_512, + SaProposal.PSEUDORANDOM_FUNCTION_SHA2_384, + SaProposal.PSEUDORANDOM_FUNCTION_SHA2_256, + SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1, + SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC))); + } + + protected final LinkedHashSet<Integer> mProposedDhGroups = new LinkedHashSet<>(); + protected final LinkedHashSet<Integer> mProposedIntegrityAlgos = new LinkedHashSet<>(); + protected final LinkedHashSet<Pair<Integer, Integer>> mProposedEncryptAlgos = + new LinkedHashSet<>(); + protected final LinkedHashSet<Pair<Integer, Integer>> mProposedAeadAlgos = + new LinkedHashSet<>(); + + /** + * Add proposed DH groups by the carrier. + * + * @param dhGroups proposed DH groups + */ + public void addProposedDhGroups(int[] dhGroups) { + for (int dhGroup : dhGroups) { + if (validateConfig(dhGroup, VALID_DH_GROUPS, CONFIG_TYPE_DH_GROUP)) { + mProposedDhGroups.add(dhGroup); + } + } + } + + /** + * Add proposed integrity algorithms by the carrier. + * + * @param integrityAlgos proposed integrity algorithms + */ + public void addProposedIntegrityAlgorithm(int[] integrityAlgos) { + for (int integrityAlgo : integrityAlgos) { + if (validateConfig(integrityAlgo, VALID_INTEGRITY_ALGOS, CONFIG_TYPE_INTEGRITY_ALGO)) { + mProposedIntegrityAlgos.add(integrityAlgo); + } + } + } + + /** + * Add proposed encryption algorithms and respective key lengths by the carrier. + * + * @param encryptionAlgo proposed encryption algorithm + * @param keyLens proposed key lengths for the encryption algorithm + */ + public void addProposedEncryptionAlgorithm(int encryptionAlgo, int[] keyLens) { + if (validateConfig(encryptionAlgo, VALID_ENCRYPTION_ALGOS, CONFIG_TYPE_ENCRYPT_ALGO)) { + for (int keyLen : keyLens) { + if (validateConfig(keyLen, VALID_KEY_LENGTHS, CONFIG_TYPE_KEY_LEN)) { + mProposedEncryptAlgos.add(new Pair<Integer, Integer>(encryptionAlgo, keyLen)); + } + } + } + } + + /** + * Add proposed AEAD algorithms and respective key lengths by the carrier. + * + * @param aeadAlgo proposed AEAD algorithm + * @param keyLens proposed key lengths for the encryption algorithm + */ + public void addProposedAeadAlgorithm(int aeadAlgo, int[] keyLens) { + if (validateConfig(aeadAlgo, VALID_AEAD_ALGOS, CONFIG_TYPE_AEAD_ALGO)) { + for (int keyLen : keyLens) { + if (validateConfig(keyLen, VALID_KEY_LENGTHS, CONFIG_TYPE_KEY_LEN)) { + mProposedAeadAlgos.add(new Pair<Integer, Integer>(aeadAlgo, keyLen)); + } + } + } + } + + /** Enable to reorder proposals with safer ciphers prioritized. */ + public void enableReorderingSaferProposals() { + mSaferAlgosPrioritized = true; + } + + /** + * Disable to reorder proposals with safer ciphers prioritized.Follows default configured order. + */ + public void disableReorderingSaferProposals() { + mSaferAlgosPrioritized = false; + } + + protected boolean isSaferProposalsPrioritized() { + return mSaferAlgosPrioritized; + } + + protected int getIndexOf(Set<Integer> set, int value) { + Iterator<Integer> itr = set.iterator(); + int index = 0; + + while (itr.hasNext()) { + if (itr.next().equals(value)) { + return index; + } + index++; + } + + return -1; + } + + /** + * Compares the priority of the transforms. + */ + protected int compareTransformPriority(Set<Integer> transformGroup, int item1, int item2) { + return getIndexOf(transformGroup, item1) - getIndexOf(transformGroup, item2); + } + + /** + * Compares the priority of the encryption/AEAD transforms. + * First value in pair is encryption/AEAD algorithm and + * second value in pair is key length of that algorithm. + * If Algorithms are same then compare the priotity of the key lengths else compare + * the priority of the algorithms. + */ + protected int compareEncryptionTransformPriority( + Set<Integer> algos, + Set<Integer> keyLens, + Pair<Integer, Integer> item1, + Pair<Integer, Integer> item2) { + return item1.first.equals(item2.first) + ? getIndexOf(keyLens, item1.second) - getIndexOf(keyLens, item2.second) + : getIndexOf(algos, item1.first) - getIndexOf(algos, item2.first); + } + + protected int[] getDhGroups() { + if (isSaferProposalsPrioritized()) { + return mProposedDhGroups.stream() + .sorted( + (item1, item2) -> + compareTransformPriority(VALID_DH_GROUPS, item1, item2)) + .mapToInt(Integer::intValue) + .toArray(); + } + + return mProposedDhGroups.stream().mapToInt(Integer::intValue).toArray(); + } + + protected int[] getSupportedDhGroups() { + return VALID_DH_GROUPS.stream().mapToInt(Integer::intValue).toArray(); + } + + protected int[] getIntegrityAlgos() { + if (isSaferProposalsPrioritized()) { + return mProposedIntegrityAlgos.stream() + .sorted( + (item1, item2) -> + compareTransformPriority(VALID_INTEGRITY_ALGOS, item1, item2)) + .mapToInt(Integer::intValue) + .toArray(); + } + + return mProposedIntegrityAlgos.stream().mapToInt(Integer::intValue).toArray(); + } + + protected int[] getSupportedIntegrityAlgos() { + return VALID_INTEGRITY_ALGOS.stream().mapToInt(Integer::intValue).toArray(); + } + + protected Pair<Integer, Integer>[] getEncryptionAlgos() { + if (isSaferProposalsPrioritized()) { + return mProposedEncryptAlgos.stream() + .sorted( + (item1, item2) -> + compareEncryptionTransformPriority( + VALID_ENCRYPTION_ALGOS, + VALID_KEY_LENGTHS, + item1, + item2)) + .toArray(Pair[]::new); + } + + return mProposedEncryptAlgos.toArray(new Pair[mProposedEncryptAlgos.size()]); + } + + protected Pair<Integer, Integer>[] getSupportedEncryptionAlgos() { + Pair<Integer, Integer>[] encrAlgos = + new Pair[VALID_ENCRYPTION_ALGOS.size() * VALID_KEY_LENGTHS.size()]; + int index = 0; + for (int algo : VALID_ENCRYPTION_ALGOS) { + for (int len : VALID_KEY_LENGTHS) { + encrAlgos[index++] = new Pair(algo, len); + } + } + + return encrAlgos; + } + + protected Pair<Integer, Integer>[] getAeadAlgos() { + if (isSaferProposalsPrioritized()) { + return mProposedAeadAlgos.stream() + .sorted( + (item1, item2) -> + compareEncryptionTransformPriority( + VALID_AEAD_ALGOS, VALID_KEY_LENGTHS, item1, item2)) + .toArray(Pair[]::new); + } + + return mProposedAeadAlgos.toArray(new Pair[mProposedAeadAlgos.size()]); + } + + protected Pair<Integer, Integer>[] getSupportedAeadAlgos() { + Pair<Integer, Integer>[] aeadAlgos = + new Pair[VALID_AEAD_ALGOS.size() * VALID_KEY_LENGTHS.size()]; + int index = 0; + for (int algo : VALID_AEAD_ALGOS) { + for (int len : VALID_KEY_LENGTHS) { + aeadAlgos[index++] = new Pair(algo, len); + } + } + + return aeadAlgos; + } + + protected static boolean validateConfig( + int config, Set<Integer> validConfigValues, String configType) { + if (validConfigValues.contains(config)) { + return true; + } + + Log.e(TAG, "Invalid config value for " + configType + ":" + config); + return false; + } +} diff --git a/src/com/google/android/iwlan/epdg/EpdgSelector.java b/src/com/google/android/iwlan/epdg/EpdgSelector.java index 3db6ac2..dc2c364 100644 --- a/src/com/google/android/iwlan/epdg/EpdgSelector.java +++ b/src/com/google/android/iwlan/epdg/EpdgSelector.java @@ -68,6 +68,7 @@ import java.util.concurrent.SynchronousQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import java.util.regex.Pattern; import java.util.stream.Collectors; public class EpdgSelector { @@ -101,6 +102,7 @@ public class EpdgSelector { private static final int PCO_IPV6_LEN = 16; // 16 bytes for IPv6 address in PCO data. private static final String NO_DOMAIN = "NO_DOMAIN"; + private static final Pattern PLMN_PATTERN = Pattern.compile("\\d{5,6}"); BlockingQueue<Runnable> dnsResolutionQueue; @@ -153,6 +155,9 @@ public class EpdgSelector { mV4PcoData = new ArrayList<>(); mV6PcoData = new ArrayList<>(); + mV4PcoData = new ArrayList<>(); + mV6PcoData = new ArrayList<>(); + mErrorPolicyManager = ErrorPolicyManager.getInstance(mContext, mSlotId); mTemporaryExcludedAddresses = new HashSet<>(); @@ -1388,6 +1393,6 @@ public class EpdgSelector { * @return True if the PLMN identifier is valid, false otherwise. */ private static boolean isValidPlmn(String plmn) { - return plmn != null && plmn.matches("\\d{5,6}"); + return plmn != null && PLMN_PATTERN.matcher(plmn).matches(); } } diff --git a/src/com/google/android/iwlan/epdg/EpdgTunnelManager.java b/src/com/google/android/iwlan/epdg/EpdgTunnelManager.java index 47f3fa3..8b53ee1 100644 --- a/src/com/google/android/iwlan/epdg/EpdgTunnelManager.java +++ b/src/com/google/android/iwlan/epdg/EpdgTunnelManager.java @@ -76,6 +76,7 @@ import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.google.android.iwlan.ErrorPolicyManager; +import com.google.android.iwlan.IwlanCarrierConfig; import com.google.android.iwlan.IwlanError; import com.google.android.iwlan.IwlanHelper; import com.google.android.iwlan.IwlanTunnelMetricsImpl; @@ -187,6 +188,7 @@ public class EpdgTunnelManager { private static final Set<Integer> VALID_PRF_ALGOS; private static final Set<Integer> VALID_INTEGRITY_ALGOS; private static final Set<Integer> VALID_ENCRYPTION_ALGOS; + private static final Set<Integer> VALID_AEAD_ALGOS; private static final String CONFIG_TYPE_DH_GROUP = "dh group"; private static final String CONFIG_TYPE_KEY_LEN = "algorithm key length"; @@ -221,6 +223,12 @@ public class EpdgTunnelManager { SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_384_192, SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_512_256); + VALID_AEAD_ALGOS = + Set.of( + SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8, + SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12, + SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16); + VALID_PRF_ALGOS = Set.of( SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1, @@ -237,11 +245,19 @@ public class EpdgTunnelManager { public static final int BRINGDOWN_REASON_UNKNOWN = 0; public static final int BRINGDOWN_REASON_DISABLE_N1_MODE = 1; public static final int BRINGDOWN_REASON_ENABLE_N1_MODE = 2; + public static final int BRINGDOWN_REASON_SERVICE_OUT_OF_SYNC = 3; + public static final int BRINGDOWN_REASON_IN_DEACTIVATING_STATE = 4; + public static final int BRINGDOWN_REASON_NETWORK_UPDATE_WHEN_TUNNEL_IN_BRINGUP = 5; + public static final int BRINGDOWN_REASON_DEACTIVATE_DATA_CALL = 6; @IntDef({ BRINGDOWN_REASON_UNKNOWN, BRINGDOWN_REASON_DISABLE_N1_MODE, BRINGDOWN_REASON_ENABLE_N1_MODE, + BRINGDOWN_REASON_SERVICE_OUT_OF_SYNC, + BRINGDOWN_REASON_IN_DEACTIVATING_STATE, + BRINGDOWN_REASON_NETWORK_UPDATE_WHEN_TUNNEL_IN_BRINGUP, + BRINGDOWN_REASON_DEACTIVATE_DATA_CALL, }) public @interface TunnelBringDownReason {} @@ -253,6 +269,14 @@ public class EpdgTunnelManager { return "BRINGDOWN_REASON_DISABLE_N1_MODE"; case BRINGDOWN_REASON_ENABLE_N1_MODE: return "BRINGDOWN_REASON_ENABLE_N1_MODE"; + case BRINGDOWN_REASON_SERVICE_OUT_OF_SYNC: + return "BRINGDOWN_REASON_SERVICE_OUT_OF_SYNC"; + case BRINGDOWN_REASON_IN_DEACTIVATING_STATE: + return "BRINGDOWN_REASON_IN_DEACTIVATING_STATE"; + case BRINGDOWN_REASON_NETWORK_UPDATE_WHEN_TUNNEL_IN_BRINGUP: + return "BRINGDOWN_REASON_NETWORK_UPDATE_WHEN_TUNNEL_IN_BRINGUP"; + case BRINGDOWN_REASON_DEACTIVATE_DATA_CALL: + return "BRINGDOWN_REASON_DEACTIVATE_DATA_CALL"; default: return "Unknown(" + reason + ")"; } @@ -693,24 +717,6 @@ public class EpdgTunnelManager { * provided in {@link #bringUpTunnel}. If no tunnel was available, callback will be delivered * using client-provided provided tunnelCallback and iwlanTunnelMetrics * - * @param apnName apn name - * @param forceClose if true, results in local cleanup of tunnel - * @param tunnelCallback Used if no current or pending IWLAN tunnel exists - * @param iwlanTunnelMetrics Used to report metrics if no current or pending IWLAN tunnel exists - */ - // TODO(b/309866889): Clarify tunnel bring down reason for tunnel closure. - public void closeTunnel( - @NonNull String apnName, - boolean forceClose, - @NonNull TunnelCallback tunnelCallback, - @NonNull IwlanTunnelMetricsImpl iwlanTunnelMetrics) { - closeTunnel( - apnName, forceClose, tunnelCallback, iwlanTunnelMetrics, BRINGDOWN_REASON_UNKNOWN); - } - - /** - * Closes tunnel for an apn with reason. - * * @param apnName APN name * @param forceClose if {@code true}, triggers a local cleanup of the tunnel; if {@code false}, * performs a normal closure procedure @@ -920,7 +926,35 @@ public class EpdgTunnelManager { new TunnelModeChildSessionParams.Builder() .setLifetimeSeconds(hardTimeSeconds, softTimeSeconds); - childSessionParamsBuilder.addChildSaProposal(buildChildSaProposal()); + if (mFeatureFlags.multipleSaProposals() + && IwlanCarrierConfig.getConfigBoolean( + mContext, + mSlotId, + CarrierConfigManager.Iwlan + .KEY_SUPPORTS_CHILD_SESSION_MULTIPLE_SA_PROPOSALS_BOOL)) { + EpdgChildSaProposal epdgChildSaProposal = createEpdgChildSaProposal(); + + if (mFeatureFlags.highSecureTransformsPrioritized()) { + epdgChildSaProposal.enableReorderingSaferProposals(); + } + + if (isChildSessionAeadAlgosAvailable()) { + childSessionParamsBuilder.addChildSaProposal( + epdgChildSaProposal.buildProposedChildSaAeadProposal()); + } + childSessionParamsBuilder.addChildSaProposal( + epdgChildSaProposal.buildProposedChildSaProposal()); + childSessionParamsBuilder.addChildSaProposal( + epdgChildSaProposal.buildSupportedChildSaAeadProposal()); + childSessionParamsBuilder.addChildSaProposal( + epdgChildSaProposal.buildSupportedChildSaProposal()); + } else { + if (mFeatureFlags.aeadAlgosEnabled() && isChildSessionAeadAlgosAvailable()) { + childSessionParamsBuilder.addChildSaProposal(buildAeadChildSaProposal()); + } else { + childSessionParamsBuilder.addChildSaProposal(buildChildSaProposal()); + } + } boolean handoverIPv4Present = setupRequest.srcIpv4Address().isPresent(); boolean handoverIPv6Present = setupRequest.srcIpv6Address().isPresent(); @@ -1049,7 +1083,6 @@ public class EpdgTunnelManager { .setLocalIdentification(getLocalIdentification()) .setRemoteIdentification(getId(setupRequest.apnName(), false)) .setAuthEap(null, getEapConfig()) - .addIkeSaProposal(buildIkeSaProposal()) .setNetwork(mDefaultNetwork) .addIkeOption(IkeSessionParams.IKE_OPTION_ACCEPT_ANY_REMOTE_ID) .addIkeOption(IkeSessionParams.IKE_OPTION_MOBIKE) @@ -1058,6 +1091,32 @@ public class EpdgTunnelManager { .setRetransmissionTimeoutsMillis(getRetransmissionTimeoutsFromConfig()) .setDpdDelaySeconds(getDpdDelayFromConfig()); + if (mFeatureFlags.multipleSaProposals() + && IwlanCarrierConfig.getConfigBoolean( + mContext, + mSlotId, + CarrierConfigManager.Iwlan + .KEY_SUPPORTS_IKE_SESSION_MULTIPLE_SA_PROPOSALS_BOOL)) { + EpdgIkeSaProposal epdgIkeSaProposal = createEpdgIkeSaProposal(); + + if (mFeatureFlags.highSecureTransformsPrioritized()) { + epdgIkeSaProposal.enableReorderingSaferProposals(); + } + + if (isIkeSessionAeadAlgosAvailable()) { + builder.addIkeSaProposal(epdgIkeSaProposal.buildProposedIkeSaAeadProposal()); + } + builder.addIkeSaProposal(epdgIkeSaProposal.buildProposedIkeSaProposal()); + builder.addIkeSaProposal(epdgIkeSaProposal.buildSupportedIkeSaAeadProposal()); + builder.addIkeSaProposal(epdgIkeSaProposal.buildSupportedIkeSaProposal()); + } else { + if (mFeatureFlags.aeadAlgosEnabled() && isIkeSessionAeadAlgosAvailable()) { + builder.addIkeSaProposal(buildIkeSaAeadProposal()); + } else { + builder.addIkeSaProposal(buildIkeSaProposal()); + } + } + if (numPdnTunnels() == 0) { builder.addIkeOption(IkeSessionParams.IKE_OPTION_INITIAL_CONTACT); Log.d(TAG, "IKE_OPTION_INITIAL_CONTACT"); @@ -1122,6 +1181,32 @@ public class EpdgTunnelManager { builder3gppParams.build(), new TmIke3gppCallback(apnName, token)); } + private boolean isChildSessionAeadAlgosAvailable() { + int[] encryptionAlgos = + getConfig( + CarrierConfigManager.Iwlan + .KEY_SUPPORTED_CHILD_SESSION_AEAD_ALGORITHMS_INT_ARRAY); + for (int encryptionAlgo : encryptionAlgos) { + if (validateConfig(encryptionAlgo, VALID_AEAD_ALGOS, CONFIG_TYPE_ENCRYPT_ALGO)) { + return true; + } + } + return false; + } + + private boolean isIkeSessionAeadAlgosAvailable() { + int[] encryptionAlgos = + getConfig( + CarrierConfigManager.Iwlan + .KEY_SUPPORTED_IKE_SESSION_AEAD_ALGORITHMS_INT_ARRAY); + for (int encryptionAlgo : encryptionAlgos) { + if (validateConfig(encryptionAlgo, VALID_AEAD_ALGOS, CONFIG_TYPE_ENCRYPT_ALGO)) { + return true; + } + } + return false; + } + private boolean isValidChildSessionLifetime(int hardLifetimeSeconds, int softLifetimeSeconds) { return hardLifetimeSeconds >= CHILD_HARD_LIFETIME_SEC_MINIMUM && hardLifetimeSeconds <= CHILD_HARD_LIFETIME_SEC_MAXIMUM @@ -1140,6 +1225,124 @@ public class EpdgTunnelManager { return IwlanHelper.getConfig(configKey, mContext, mSlotId); } + private void createEpdgSaProposal(EpdgSaProposal epdgSaProposal, boolean isChildProposal) { + epdgSaProposal.addProposedDhGroups( + IwlanCarrierConfig.getConfigIntArray( + mContext, + mSlotId, + CarrierConfigManager.Iwlan.KEY_DIFFIE_HELLMAN_GROUPS_INT_ARRAY)); + + int[] encryptionAlgos = + isChildProposal + ? IwlanCarrierConfig.getConfigIntArray( + mContext, + mSlotId, + CarrierConfigManager.Iwlan + .KEY_SUPPORTED_CHILD_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY) + : IwlanCarrierConfig.getConfigIntArray( + mContext, + mSlotId, + CarrierConfigManager.Iwlan + .KEY_SUPPORTED_IKE_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY); + + for (int encryptionAlgo : encryptionAlgos) { + if (encryptionAlgo == SaProposal.ENCRYPTION_ALGORITHM_AES_CBC) { + int[] aesCbcKeyLens = + isChildProposal + ? IwlanCarrierConfig.getConfigIntArray( + mContext, + mSlotId, + CarrierConfigManager.Iwlan + .KEY_CHILD_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY) + : IwlanCarrierConfig.getConfigIntArray( + mContext, + mSlotId, + CarrierConfigManager.Iwlan + .KEY_IKE_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY); + epdgSaProposal.addProposedEncryptionAlgorithm(encryptionAlgo, aesCbcKeyLens); + } + + if (encryptionAlgo == SaProposal.ENCRYPTION_ALGORITHM_AES_CTR) { + int[] aesCtrKeyLens = + isChildProposal + ? IwlanCarrierConfig.getConfigIntArray( + mContext, + mSlotId, + CarrierConfigManager.Iwlan + .KEY_CHILD_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY) + : IwlanCarrierConfig.getConfigIntArray( + mContext, + mSlotId, + CarrierConfigManager.Iwlan + .KEY_IKE_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY); + epdgSaProposal.addProposedEncryptionAlgorithm(encryptionAlgo, aesCtrKeyLens); + } + } + + if (encryptionAlgos.length > 0) { + epdgSaProposal.addProposedIntegrityAlgorithm( + IwlanCarrierConfig.getConfigIntArray( + mContext, + mSlotId, + CarrierConfigManager.Iwlan + .KEY_SUPPORTED_INTEGRITY_ALGORITHMS_INT_ARRAY)); + } + + int[] aeadAlgos = + isChildProposal + ? IwlanCarrierConfig.getConfigIntArray( + mContext, + mSlotId, + CarrierConfigManager.Iwlan + .KEY_SUPPORTED_CHILD_SESSION_AEAD_ALGORITHMS_INT_ARRAY) + : IwlanCarrierConfig.getConfigIntArray( + mContext, + mSlotId, + CarrierConfigManager.Iwlan + .KEY_SUPPORTED_IKE_SESSION_AEAD_ALGORITHMS_INT_ARRAY); + for (int aeadAlgo : aeadAlgos) { + if (!validateConfig(aeadAlgo, VALID_AEAD_ALGOS, CONFIG_TYPE_ENCRYPT_ALGO)) { + continue; + } + if ((aeadAlgo == SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8) + || (aeadAlgo == SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12) + || (aeadAlgo == SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16)) { + int[] aesGcmKeyLens = + isChildProposal + ? IwlanCarrierConfig.getConfigIntArray( + mContext, + mSlotId, + CarrierConfigManager.Iwlan + .KEY_CHILD_SESSION_AES_GCM_KEY_SIZE_INT_ARRAY) + : IwlanCarrierConfig.getConfigIntArray( + mContext, + mSlotId, + CarrierConfigManager.Iwlan + .KEY_IKE_SESSION_AES_GCM_KEY_SIZE_INT_ARRAY); + epdgSaProposal.addProposedAeadAlgorithm(aeadAlgo, aesGcmKeyLens); + } + } + } + + private EpdgChildSaProposal createEpdgChildSaProposal() { + EpdgChildSaProposal epdgChildSaProposal = new EpdgChildSaProposal(); + createEpdgSaProposal(epdgChildSaProposal, true); + return epdgChildSaProposal; + } + + private EpdgIkeSaProposal createEpdgIkeSaProposal() { + EpdgIkeSaProposal epdgIkeSaProposal = new EpdgIkeSaProposal(); + + createEpdgSaProposal(epdgIkeSaProposal, false); + + epdgIkeSaProposal.addProposedPrfAlgorithm( + IwlanCarrierConfig.getConfigIntArray( + mContext, + mSlotId, + CarrierConfigManager.Iwlan.KEY_SUPPORTED_PRF_ALGORITHMS_INT_ARRAY)); + return epdgIkeSaProposal; + } + private IkeSaProposal buildIkeSaProposal() { IkeSaProposal.Builder saProposalBuilder = new IkeSaProposal.Builder(); @@ -1201,6 +1404,50 @@ public class EpdgTunnelManager { return saProposalBuilder.build(); } + private IkeSaProposal buildIkeSaAeadProposal() { + IkeSaProposal.Builder saProposalBuilder = new IkeSaProposal.Builder(); + + int[] dhGroups = getConfig(CarrierConfigManager.Iwlan.KEY_DIFFIE_HELLMAN_GROUPS_INT_ARRAY); + for (int dhGroup : dhGroups) { + if (validateConfig(dhGroup, VALID_DH_GROUPS, CONFIG_TYPE_DH_GROUP)) { + saProposalBuilder.addDhGroup(dhGroup); + } + } + + int[] encryptionAlgos = + getConfig( + CarrierConfigManager.Iwlan + .KEY_SUPPORTED_IKE_SESSION_AEAD_ALGORITHMS_INT_ARRAY); + for (int encryptionAlgo : encryptionAlgos) { + if (!validateConfig(encryptionAlgo, VALID_AEAD_ALGOS, CONFIG_TYPE_ENCRYPT_ALGO)) { + continue; + } + if ((encryptionAlgo == SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8) + || (encryptionAlgo == SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12) + || (encryptionAlgo == SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16)) { + int[] aesGcmKeyLens = + getConfig( + CarrierConfigManager.Iwlan + .KEY_IKE_SESSION_AES_GCM_KEY_SIZE_INT_ARRAY); + for (int aesGcmKeyLen : aesGcmKeyLens) { + if (validateConfig(aesGcmKeyLen, VALID_KEY_LENGTHS, CONFIG_TYPE_KEY_LEN)) { + saProposalBuilder.addEncryptionAlgorithm(encryptionAlgo, aesGcmKeyLen); + } + } + } + } + + int[] prfAlgos = + getConfig(CarrierConfigManager.Iwlan.KEY_SUPPORTED_PRF_ALGORITHMS_INT_ARRAY); + for (int prfAlgo : prfAlgos) { + if (validateConfig(prfAlgo, VALID_PRF_ALGOS, CONFIG_TYPE_PRF_ALGO)) { + saProposalBuilder.addPseudorandomFunction(prfAlgo); + } + } + + return saProposalBuilder.build(); + } + private boolean validateConfig(int config, Set<Integer> validConfigValues, String configType) { if (validConfigValues.contains(config)) { return true; @@ -1280,6 +1527,42 @@ public class EpdgTunnelManager { return saProposalBuilder.build(); } + private ChildSaProposal buildAeadChildSaProposal() { + ChildSaProposal.Builder saProposalBuilder = new ChildSaProposal.Builder(); + + int[] dhGroups = getConfig(CarrierConfigManager.Iwlan.KEY_DIFFIE_HELLMAN_GROUPS_INT_ARRAY); + for (int dhGroup : dhGroups) { + if (validateConfig(dhGroup, VALID_DH_GROUPS, CONFIG_TYPE_DH_GROUP)) { + saProposalBuilder.addDhGroup(dhGroup); + } + } + + int[] encryptionAlgos = + getConfig( + CarrierConfigManager.Iwlan + .KEY_SUPPORTED_CHILD_SESSION_AEAD_ALGORITHMS_INT_ARRAY); + for (int encryptionAlgo : encryptionAlgos) { + if (!validateConfig(encryptionAlgo, VALID_AEAD_ALGOS, CONFIG_TYPE_ENCRYPT_ALGO)) { + continue; + } + if ((encryptionAlgo == SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8) + || (encryptionAlgo == SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12) + || (encryptionAlgo == SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16)) { + int[] aesGcmKeyLens = + getConfig( + CarrierConfigManager.Iwlan + .KEY_CHILD_SESSION_AES_GCM_KEY_SIZE_INT_ARRAY); + for (int aesGcmKeyLen : aesGcmKeyLens) { + if (validateConfig(aesGcmKeyLen, VALID_KEY_LENGTHS, CONFIG_TYPE_KEY_LEN)) { + saProposalBuilder.addEncryptionAlgorithm(encryptionAlgo, aesGcmKeyLen); + } + } + } + } + + return saProposalBuilder.build(); + } + private IkeIdentification getLocalIdentification() throws IwlanSimNotReadyException { String nai; diff --git a/test/com/google/android/iwlan/IwlanDataServiceTest.java b/test/com/google/android/iwlan/IwlanDataServiceTest.java index f5914d9..6168b82 100644 --- a/test/com/google/android/iwlan/IwlanDataServiceTest.java +++ b/test/com/google/android/iwlan/IwlanDataServiceTest.java @@ -27,6 +27,9 @@ import static android.telephony.TelephonyManager.NETWORK_TYPE_BITMASK_NR; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; +import static com.google.android.iwlan.epdg.EpdgTunnelManager.BRINGDOWN_REASON_DEACTIVATE_DATA_CALL; +import static com.google.android.iwlan.epdg.EpdgTunnelManager.BRINGDOWN_REASON_NETWORK_UPDATE_WHEN_TUNNEL_IN_BRINGUP; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; @@ -142,7 +145,6 @@ public class IwlanDataServiceTest { @Mock private LinkAddress mMockIPv6LinkAddress; @Mock private Inet4Address mMockInet4Address; @Mock private Inet6Address mMockInet6Address; - @Mock private CarrierConfigManager mMockCarrierConfigManager; @Mock private FeatureFlags mFakeFeatureFlags; MockitoSession mStaticMockSession; @@ -213,7 +215,6 @@ public class IwlanDataServiceTest { .mockStatic(ErrorPolicyManager.class) .mockStatic(IwlanBroadcastReceiver.class) .mockStatic(SubscriptionManager.class) - .mockStatic(IwlanCarrierConfig.class) .strictness(Strictness.LENIENT) .startMocking(); @@ -262,8 +263,6 @@ public class IwlanDataServiceTest { mIwlanDataService = spy(new IwlanDataService(mFakeFeatureFlags)); - when(mMockContext.getSystemService(eq(CarrierConfigManager.class))) - .thenReturn(mMockCarrierConfigManager); // Injects the test looper into the IwlanDataServiceHandler doReturn(mTestLooper.getLooper()).when(mIwlanDataService).getLooper(); mIwlanDataService.setAppContext(mMockContext); @@ -281,8 +280,9 @@ public class IwlanDataServiceTest { when(mMockConnectivityManager.getLinkProperties(eq(mMockNetwork))) .thenReturn(mLinkProperties); - when(mMockTunnelLinkProperties.ifaceName()).thenReturn("mockipsec0"); + + mockCarrierConfigForN1Mode(true); } private void moveTimeForwardAndDispatch(long milliSeconds) { @@ -293,6 +293,7 @@ public class IwlanDataServiceTest { @After public void cleanUp() throws Exception { mStaticMockSession.finishMocking(); + IwlanCarrierConfig.resetTestConfig(); mSpyIwlanDataServiceProvider.close(); mTestLooper.dispatchAll(); if (mIwlanDataService != null) { @@ -458,7 +459,8 @@ public class IwlanDataServiceTest { networkCallback.onLinkPropertiesChanged(mMockNetwork, newLinkProperties); verify(mMockEpdgTunnelManager, times(1)) .updateNetwork(eq(mMockNetwork), eq(newLinkProperties)); - verify(mMockEpdgTunnelManager, never()).closeTunnel(any(), anyBoolean(), any(), any()); + verify(mMockEpdgTunnelManager, never()) + .closeTunnel(any(), anyBoolean(), any(), any(), anyInt()); } @Test @@ -867,7 +869,8 @@ public class IwlanDataServiceTest { eq(TEST_APN_NAME), eq(false), any(IwlanTunnelCallback.class), - any(IwlanTunnelMetricsImpl.class)); + any(IwlanTunnelMetricsImpl.class), + eq(BRINGDOWN_REASON_DEACTIVATE_DATA_CALL)); /* Check callback result is RESULT_SUCCESS when onClosed() is called. */ mSpyIwlanDataServiceProvider @@ -907,7 +910,8 @@ public class IwlanDataServiceTest { eq(TEST_APN_NAME), eq(true) /* forceClose */, any(IwlanTunnelCallback.class), - any(IwlanTunnelMetricsImpl.class)); + any(IwlanTunnelMetricsImpl.class), + eq(BRINGDOWN_REASON_DEACTIVATE_DATA_CALL)); /* Check callback result is RESULT_SUCCESS when onClosed() is called. */ mSpyIwlanDataServiceProvider @@ -922,11 +926,8 @@ public class IwlanDataServiceTest { public void testDeactivateDataCall_DelayedReleaseAfterHandover() { DataProfile dp = buildImsDataProfile(); - when(IwlanCarrierConfig.getConfigInt( - mMockContext, - DEFAULT_SLOT_INDEX, - IwlanCarrierConfig.KEY_HANDOVER_TO_WWAN_RELEASE_DELAY_SECOND_INT)) - .thenReturn(3); + IwlanCarrierConfig.putTestConfigInt( + IwlanCarrierConfig.KEY_HANDOVER_TO_WWAN_RELEASE_DELAY_SECOND_INT, 3); onSystemDefaultNetworkConnected(TRANSPORT_WIFI); mSpyIwlanDataServiceProvider.setTunnelState( @@ -952,7 +953,8 @@ public class IwlanDataServiceTest { eq(TEST_APN_NAME), anyBoolean(), any(IwlanTunnelCallback.class), - any(IwlanTunnelMetricsImpl.class)); + any(IwlanTunnelMetricsImpl.class), + eq(BRINGDOWN_REASON_DEACTIVATE_DATA_CALL)); moveTimeForwardAndDispatch(50); /* Check closeTunnel() is called. */ @@ -961,7 +963,8 @@ public class IwlanDataServiceTest { eq(TEST_APN_NAME), eq(true) /* forceClose */, any(IwlanTunnelCallback.class), - any(IwlanTunnelMetricsImpl.class)); + any(IwlanTunnelMetricsImpl.class), + eq(BRINGDOWN_REASON_DEACTIVATE_DATA_CALL)); /* Check callback result is RESULT_SUCCESS when onClosed() is called. */ mSpyIwlanDataServiceProvider @@ -976,11 +979,8 @@ public class IwlanDataServiceTest { public void testDeactivateDataCall_DelayedReleaseAfterHandover_NetworkReleaseBeforeDelay() { DataProfile dp = buildImsDataProfile(); - when(IwlanCarrierConfig.getConfigInt( - mMockContext, - DEFAULT_SLOT_INDEX, - IwlanCarrierConfig.KEY_HANDOVER_TO_WWAN_RELEASE_DELAY_SECOND_INT)) - .thenReturn(3); + IwlanCarrierConfig.putTestConfigInt( + IwlanCarrierConfig.KEY_HANDOVER_TO_WWAN_RELEASE_DELAY_SECOND_INT, 3); when(ErrorPolicyManager.getInstance(eq(mMockContext), eq(DEFAULT_SLOT_INDEX))) .thenReturn(mMockErrorPolicyManager); when(mMockErrorPolicyManager.getDataFailCause(eq(TEST_APN_NAME))) @@ -1020,7 +1020,8 @@ public class IwlanDataServiceTest { eq(TEST_APN_NAME), anyBoolean(), any(IwlanTunnelCallback.class), - any(IwlanTunnelMetricsImpl.class)); + any(IwlanTunnelMetricsImpl.class), + anyInt()); /* Check callback result is RESULT_SUCCESS when onClosed() is called. */ mSpyIwlanDataServiceProvider @@ -1037,7 +1038,8 @@ public class IwlanDataServiceTest { eq(TEST_APN_NAME), anyBoolean(), any(IwlanTunnelCallback.class), - any(IwlanTunnelMetricsImpl.class)); + any(IwlanTunnelMetricsImpl.class), + anyInt()); // No additional callbacks are involved. verify(mMockDataServiceCallback, times(1)).onDeactivateDataCallComplete(anyInt()); @@ -1993,7 +1995,8 @@ public class IwlanDataServiceTest { eq(TEST_APN_NAME), anyBoolean(), any(IwlanTunnelCallback.class), - any(IwlanTunnelMetricsImpl.class)); + any(IwlanTunnelMetricsImpl.class), + eq(BRINGDOWN_REASON_DEACTIVATE_DATA_CALL)); advanceCalendarByTimeMs(deactivationTime, calendar); @@ -2044,7 +2047,13 @@ public class IwlanDataServiceTest { Network newNetwork2 = createMockNetwork(mLinkProperties); onSystemDefaultNetworkConnected( newNetwork2, mLinkProperties, TRANSPORT_WIFI, DEFAULT_SUB_INDEX); - verify(mMockEpdgTunnelManager, times(1)).closeTunnel(any(), anyBoolean(), any(), any()); + verify(mMockEpdgTunnelManager, times(1)) + .closeTunnel( + any(), + anyBoolean(), + any(), + any(), + eq(BRINGDOWN_REASON_NETWORK_UPDATE_WHEN_TUNNEL_IN_BRINGUP)); } public static TunnelLinkProperties createTunnelLinkProperties() throws Exception { @@ -2072,15 +2081,6 @@ public class IwlanDataServiceTest { .build(); } - private void setupMockForGetConfig(PersistableBundle bundle) { - if (bundle == null) { - bundle = new PersistableBundle(); - } - when(mMockContext.getSystemService(eq(CarrierConfigManager.class))) - .thenReturn(mMockCarrierConfigManager); - when(mMockCarrierConfigManager.getConfigForSubId(DEFAULT_SLOT_INDEX)).thenReturn(bundle); - } - private void mockCarrierConfigForN1Mode(boolean supportN1Mode) { PersistableBundle bundle = new PersistableBundle(); if (supportN1Mode) { @@ -2095,7 +2095,7 @@ public class IwlanDataServiceTest { CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY, new int[] {CarrierConfigManager.CARRIER_NR_AVAILABILITY_NSA}); } - setupMockForGetConfig(bundle); + IwlanCarrierConfig.putTestConfigBundle(bundle); } private void mockCallState(int callState) { @@ -2132,7 +2132,7 @@ public class IwlanDataServiceTest { CarrierConfigManager.CARRIER_NR_AVAILABILITY_NSA, CarrierConfigManager.CARRIER_NR_AVAILABILITY_SA }); - setupMockForGetConfig(bundle); + IwlanCarrierConfig.putTestConfigBundle(bundle); assertTrue(mSpyIwlanDataServiceProvider.isN1ModeSupported()); bundle.putIntArray( @@ -2140,14 +2140,15 @@ public class IwlanDataServiceTest { new int[] { CarrierConfigManager.CARRIER_NR_AVAILABILITY_NSA, }); - setupMockForGetConfig(bundle); + IwlanCarrierConfig.putTestConfigBundle(bundle); assertFalse(mSpyIwlanDataServiceProvider.isN1ModeSupported()); } @Test public void testMultipleAllowedNetworkTypeChangeInIdle_updateN1Mode() throws Exception { - when(mFakeFeatureFlags.updateN1ModeOnUiChange()).thenReturn(true); mockCarrierConfigForN1Mode(true); + IwlanCarrierConfig.putTestConfigBoolean( + IwlanCarrierConfig.KEY_UPDATE_N1_MODE_ON_UI_CHANGE_BOOL, true); mockCallState(CALL_STATE_IDLE); mockSetupDataCallWithPduSessionId(0); updatePreferredNetworkType(NETWORK_TYPE_BITMASK_NR); @@ -2175,8 +2176,10 @@ public class IwlanDataServiceTest { @Test public void testMultipleAllowedNetworkTypeChangeInCall_preferenceChanged_updateAfterCallEnds() throws Exception { - when(mFakeFeatureFlags.updateN1ModeOnUiChange()).thenReturn(true); mockCarrierConfigForN1Mode(true); + IwlanCarrierConfig.putTestConfigBoolean( + IwlanCarrierConfig.KEY_UPDATE_N1_MODE_ON_UI_CHANGE_BOOL, true); + mockCallState(CALL_STATE_RINGING); mockSetupDataCallWithPduSessionId(0); updatePreferredNetworkType(NETWORK_TYPE_BITMASK_NR); @@ -2208,8 +2211,10 @@ public class IwlanDataServiceTest { @Test public void testMultipleAllowedNetworkTypeChangeInCall_preferenceNotChanged_noUpdate() throws Exception { - when(mFakeFeatureFlags.updateN1ModeOnUiChange()).thenReturn(true); mockCarrierConfigForN1Mode(true); + IwlanCarrierConfig.putTestConfigBoolean( + IwlanCarrierConfig.KEY_UPDATE_N1_MODE_ON_UI_CHANGE_BOOL, true); + mockCallState(CALL_STATE_RINGING); mockSetupDataCallWithPduSessionId(0); updatePreferredNetworkType(NETWORK_TYPE_BITMASK_NR); @@ -2234,8 +2239,10 @@ public class IwlanDataServiceTest { @Test public void testOnAllowedNetworkTypeChange_flagDisabled_noTunnelClose() { - when(mFakeFeatureFlags.updateN1ModeOnUiChange()).thenReturn(false); mockCarrierConfigForN1Mode(true); + IwlanCarrierConfig.putTestConfigBoolean( + IwlanCarrierConfig.KEY_UPDATE_N1_MODE_ON_UI_CHANGE_BOOL, false); + mockCallState(CALL_STATE_IDLE); mockSetupDataCallWithPduSessionId(0); updatePreferredNetworkType(NETWORK_TYPE_BITMASK_NR); @@ -2246,8 +2253,10 @@ public class IwlanDataServiceTest { @Test public void testOnAllowedNetworkTypeChange_n1ModeNotSupported_noTunnelClose() { - when(mFakeFeatureFlags.updateN1ModeOnUiChange()).thenReturn(true); mockCarrierConfigForN1Mode(false); + IwlanCarrierConfig.putTestConfigBoolean( + IwlanCarrierConfig.KEY_UPDATE_N1_MODE_ON_UI_CHANGE_BOOL, true); + mockCallState(CALL_STATE_IDLE); mockSetupDataCallWithPduSessionId(0); updatePreferredNetworkType(NETWORK_TYPE_BITMASK_NR); @@ -2258,8 +2267,10 @@ public class IwlanDataServiceTest { @Test public void testN1ModeNotSupported_tunnelBringupWithNoN1ModeCapability() { - when(mFakeFeatureFlags.updateN1ModeOnUiChange()).thenReturn(true); mockCarrierConfigForN1Mode(false); + IwlanCarrierConfig.putTestConfigBoolean( + IwlanCarrierConfig.KEY_UPDATE_N1_MODE_ON_UI_CHANGE_BOOL, true); + mockSetupDataCallWithPduSessionId(1); ArgumentCaptor<TunnelSetupRequest> tunnelSetupRequestCaptor = @@ -2272,8 +2283,10 @@ public class IwlanDataServiceTest { @Test public void testNoN1ModeCapabilityInOngoingDataCall_newTunnelBringup_doNotIncludeN1() { - when(mFakeFeatureFlags.updateN1ModeOnUiChange()).thenReturn(true); mockCarrierConfigForN1Mode(true); + IwlanCarrierConfig.putTestConfigBoolean( + IwlanCarrierConfig.KEY_UPDATE_N1_MODE_ON_UI_CHANGE_BOOL, true); + mockSetupDataCallWithPduSessionId(0); ArgumentCaptor<TunnelSetupRequest> tunnelSetupRequestCaptor = @@ -2325,6 +2338,7 @@ public class IwlanDataServiceTest { @Test public void testN1ModeForEmergencySession() { int pduSessionId = 5; + updatePreferredNetworkType(NETWORK_TYPE_BITMASK_NR); DataProfile dp = buildDataProfile(ApnSetting.TYPE_EMERGENCY); verifySetupDataCallRequestHandled(pduSessionId, dp); @@ -2338,11 +2352,9 @@ public class IwlanDataServiceTest { @Test public void testN1ModeExclusionForEmergencySession() { - when(IwlanCarrierConfig.getConfigBoolean( - mMockContext, - DEFAULT_SLOT_INDEX, - IwlanCarrierConfig.KEY_N1_MODE_EXCLUSION_FOR_EMERGENCY_SESSION_BOOL)) - .thenReturn(true); + IwlanCarrierConfig.putTestConfigBoolean( + IwlanCarrierConfig.KEY_N1_MODE_EXCLUSION_FOR_EMERGENCY_SESSION_BOOL, true); + updatePreferredNetworkType(NETWORK_TYPE_BITMASK_NR); DataProfile dp = buildDataProfile(ApnSetting.TYPE_EMERGENCY); verifySetupDataCallRequestHandled(5 /* pduSessionId */, dp); diff --git a/test/com/google/android/iwlan/IwlanEventListenerTest.java b/test/com/google/android/iwlan/IwlanEventListenerTest.java index a922a10..5999872 100644 --- a/test/com/google/android/iwlan/IwlanEventListenerTest.java +++ b/test/com/google/android/iwlan/IwlanEventListenerTest.java @@ -368,8 +368,6 @@ public class IwlanEventListenerTest { @SuppressLint("MissingPermission") @Test public void testDisable5gViaUi() throws Exception { - when(mFakeFeatureFlags.updateN1ModeOnUiChange()).thenReturn(true); - when(mMockHandler.obtainMessage( eq(IwlanEventListener.PREFERRED_NETWORK_TYPE_CHANGED_EVENT), eq(DEFAULT_SLOT_INDEX), @@ -393,8 +391,6 @@ public class IwlanEventListenerTest { @SuppressLint("MissingPermission") @Test public void testEnable5gViaUi() throws Exception { - when(mFakeFeatureFlags.updateN1ModeOnUiChange()).thenReturn(true); - when(mMockHandler.obtainMessage( eq(IwlanEventListener.PREFERRED_NETWORK_TYPE_CHANGED_EVENT), eq(DEFAULT_SLOT_INDEX), diff --git a/test/com/google/android/iwlan/epdg/EpdgTunnelManagerTest.java b/test/com/google/android/iwlan/epdg/EpdgTunnelManagerTest.java index b7004e7..05ab0bc 100644 --- a/test/com/google/android/iwlan/epdg/EpdgTunnelManagerTest.java +++ b/test/com/google/android/iwlan/epdg/EpdgTunnelManagerTest.java @@ -16,6 +16,8 @@ package com.google.android.iwlan.epdg; +import static com.google.android.iwlan.epdg.EpdgTunnelManager.BRINGDOWN_REASON_UNKNOWN; + import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -26,6 +28,7 @@ import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyBoolean; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.anyLong; +import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doReturn; @@ -72,6 +75,7 @@ import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.data.ApnSetting; +import android.util.Pair; import com.google.android.iwlan.IwlanError; import com.google.android.iwlan.IwlanTunnelMetricsImpl; @@ -543,6 +547,207 @@ public class EpdgTunnelManagerTest { } @Test + public void testAeadSaProposals() throws Exception { + when(mFakeFeatureFlags.aeadAlgosEnabled()).thenReturn(true); + final String apnName = "ims"; + int[] aeadAlgos = { + SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8, + SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12, + SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16, + }; + int[] aeadAlgosKeyLens = { + SaProposal.KEY_LEN_AES_128, SaProposal.KEY_LEN_AES_192, SaProposal.KEY_LEN_AES_256, + }; + + PersistableBundle bundle = new PersistableBundle(); + bundle.putIntArray( + CarrierConfigManager.Iwlan.KEY_SUPPORTED_IKE_SESSION_AEAD_ALGORITHMS_INT_ARRAY, + aeadAlgos); + bundle.putIntArray( + CarrierConfigManager.Iwlan.KEY_IKE_SESSION_AES_GCM_KEY_SIZE_INT_ARRAY, + aeadAlgosKeyLens); + bundle.putIntArray( + CarrierConfigManager.Iwlan.KEY_SUPPORTED_CHILD_SESSION_AEAD_ALGORITHMS_INT_ARRAY, + aeadAlgos); + bundle.putIntArray( + CarrierConfigManager.Iwlan.KEY_CHILD_SESSION_AES_GCM_KEY_SIZE_INT_ARRAY, + aeadAlgosKeyLens); + + setupMockForGetConfig(bundle); + + IkeSessionArgumentCaptors tunnelArgumentCaptors = + verifyBringUpTunnelWithDnsQuery(apnName, mMockDefaultNetwork); + + IkeSessionParams ikeTunnelParams = tunnelArgumentCaptors.mIkeSessionParamsCaptor.getValue(); + + List<Pair<Integer, Integer>> ikeEncrAlgos = + ikeTunnelParams.getIkeSaProposals().get(0).getEncryptionAlgorithms(); + + assertTrue(ikeEncrAlgos.contains(new Pair(aeadAlgos[0], aeadAlgosKeyLens[0]))); + assertEquals( + "IKE AEAD algorithms mismatch", + (long) aeadAlgos.length * aeadAlgosKeyLens.length, + (long) ikeEncrAlgos.size()); + + ChildSessionParams childTunnelParams = + tunnelArgumentCaptors.mChildSessionParamsCaptor.getValue(); + + List<Pair<Integer, Integer>> childEncrAlgos = + childTunnelParams.getChildSaProposals().get(0).getEncryptionAlgorithms(); + + assertTrue(childEncrAlgos.contains(new Pair(aeadAlgos[0], aeadAlgosKeyLens[0]))); + assertEquals( + "Child AEAD algorithms mismatch", + (long) aeadAlgos.length * aeadAlgosKeyLens.length, + (long) childEncrAlgos.size()); + } + + @Test + public void testMultipleSaProposals() throws Exception { + when(mFakeFeatureFlags.multipleSaProposals()).thenReturn(true); + final String apnName = "ims"; + PersistableBundle bundle = new PersistableBundle(); + + int[] aeadAlgos = { + SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12, + }; + int[] aeadAlgosKeyLens = { + SaProposal.KEY_LEN_AES_192, SaProposal.KEY_LEN_AES_256, + }; + + bundle.putIntArray( + CarrierConfigManager.Iwlan.KEY_SUPPORTED_IKE_SESSION_AEAD_ALGORITHMS_INT_ARRAY, + aeadAlgos); + bundle.putIntArray( + CarrierConfigManager.Iwlan.KEY_IKE_SESSION_AES_GCM_KEY_SIZE_INT_ARRAY, + aeadAlgosKeyLens); + bundle.putIntArray( + CarrierConfigManager.Iwlan.KEY_SUPPORTED_CHILD_SESSION_AEAD_ALGORITHMS_INT_ARRAY, + aeadAlgos); + bundle.putIntArray( + CarrierConfigManager.Iwlan.KEY_CHILD_SESSION_AES_GCM_KEY_SIZE_INT_ARRAY, + aeadAlgosKeyLens); + + bundle.putBoolean( + CarrierConfigManager.Iwlan.KEY_SUPPORTS_IKE_SESSION_MULTIPLE_SA_PROPOSALS_BOOL, + true); + bundle.putBoolean( + CarrierConfigManager.Iwlan.KEY_SUPPORTS_CHILD_SESSION_MULTIPLE_SA_PROPOSALS_BOOL, + true); + + setupMockForGetConfig(bundle); + + IkeSessionArgumentCaptors tunnelArgumentCaptors = + verifyBringUpTunnelWithDnsQuery(apnName, mMockDefaultNetwork); + + IkeSessionParams ikeTunnelParams = tunnelArgumentCaptors.mIkeSessionParamsCaptor.getValue(); + + assertTrue(ikeTunnelParams.getIkeSaProposals().size() > 1); + + List<Pair<Integer, Integer>> ikeAeadAlgos = + ikeTunnelParams.getIkeSaProposals().get(0).getEncryptionAlgorithms(); + assertEquals( + "Reorder higher AEAD in IKE SA mismatch", + (long) SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12, + (long) ikeAeadAlgos.get(0).first); + + ChildSessionParams childTunnelParams = + tunnelArgumentCaptors.mChildSessionParamsCaptor.getValue(); + + assertTrue(childTunnelParams.getChildSaProposals().size() > 1); + + List<Pair<Integer, Integer>> childAeadAlgos = + childTunnelParams.getChildSaProposals().get(0).getEncryptionAlgorithms(); + assertEquals( + "Reorder higher AEAD in Child SA mismatch", + (long) SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12, + (long) childAeadAlgos.get(0).first); + } + + @Test + public void testSaProposalsReorder() throws Exception { + when(mFakeFeatureFlags.aeadAlgosEnabled()).thenReturn(true); + when(mFakeFeatureFlags.multipleSaProposals()).thenReturn(true); + when(mFakeFeatureFlags.highSecureTransformsPrioritized()).thenReturn(true); + + final String apnName = "ims"; + int[] aeadAlgos = { + SaProposal.ENCRYPTION_ALGORITHM_AES_CBC, + }; + int[] aeadAlgosKeyLens = { + SaProposal.KEY_LEN_AES_128, SaProposal.KEY_LEN_AES_192, SaProposal.KEY_LEN_AES_256, + }; + + PersistableBundle bundle = new PersistableBundle(); + + bundle.putIntArray( + CarrierConfigManager.Iwlan + .KEY_SUPPORTED_IKE_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY, + aeadAlgos); + bundle.putIntArray( + CarrierConfigManager.Iwlan.KEY_IKE_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY, + aeadAlgosKeyLens); + bundle.putIntArray( + CarrierConfigManager.Iwlan + .KEY_SUPPORTED_CHILD_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY, + aeadAlgos); + bundle.putIntArray( + CarrierConfigManager.Iwlan.KEY_CHILD_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY, + aeadAlgosKeyLens); + + bundle.putBoolean( + CarrierConfigManager.Iwlan.KEY_SUPPORTS_IKE_SESSION_MULTIPLE_SA_PROPOSALS_BOOL, + true); + bundle.putBoolean( + CarrierConfigManager.Iwlan.KEY_SUPPORTS_CHILD_SESSION_MULTIPLE_SA_PROPOSALS_BOOL, + true); + + setupMockForGetConfig(bundle); + + IkeSessionArgumentCaptors tunnelArgumentCaptors = + verifyBringUpTunnelWithDnsQuery(apnName, mMockDefaultNetwork); + + IkeSessionParams ikeTunnelParams = tunnelArgumentCaptors.mIkeSessionParamsCaptor.getValue(); + + assertTrue(ikeTunnelParams.getIkeSaProposals().size() > 1); + + List<Pair<Integer, Integer>> ikeEncrAlgos = + ikeTunnelParams.getIkeSaProposals().get(0).getEncryptionAlgorithms(); + + assertEquals( + "Reorder bigger key length in IKE SA mismatch", + (long) SaProposal.KEY_LEN_AES_256, + (long) ikeEncrAlgos.get(0).second); + + List<Pair<Integer, Integer>> ikeAeadAlgos = + ikeTunnelParams.getIkeSaProposals().get(1).getEncryptionAlgorithms(); + assertEquals( + "Reorder higher AEAD in IKE SA mismatch", + (long) SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16, + (long) ikeAeadAlgos.get(0).first); + + ChildSessionParams childTunnelParams = + tunnelArgumentCaptors.mChildSessionParamsCaptor.getValue(); + + assertTrue(childTunnelParams.getChildSaProposals().size() > 1); + + List<Pair<Integer, Integer>> childEncrAlgos = + childTunnelParams.getChildSaProposals().get(0).getEncryptionAlgorithms(); + + assertEquals( + "Reorder bigger key length in Child SA mismatch", + (long) SaProposal.KEY_LEN_AES_256, + (long) childEncrAlgos.get(0).second); + + List<Pair<Integer, Integer>> childAeadAlgos = + childTunnelParams.getChildSaProposals().get(1).getEncryptionAlgorithms(); + assertEquals( + "Reorder higher AEAD in Child SA mismatch", + (long) SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16, + (long) childAeadAlgos.get(0).first); + } + + @Test public void testCloseTunnelWithNoTunnelForApn() throws Exception { String testApnName = "www.xyz.com"; doReturn(0L) @@ -553,7 +758,8 @@ public class EpdgTunnelManagerTest { testApnName, false /*forceClose*/, mMockIwlanTunnelCallback, - mMockIwlanTunnelMetrics); + mMockIwlanTunnelMetrics, + BRINGDOWN_REASON_UNKNOWN); mTestLooper.dispatchAll(); verify(mEpdgTunnelManager).closePendingRequestsForApn(eq(testApnName)); @@ -582,7 +788,8 @@ public class EpdgTunnelManagerTest { testApnName, true /*forceClose*/, mMockIwlanTunnelCallback, - mMockIwlanTunnelMetrics); + mMockIwlanTunnelMetrics, + BRINGDOWN_REASON_UNKNOWN); mTestLooper.dispatchAll(); verify(mMockIkeSession).kill(); @@ -606,7 +813,8 @@ public class EpdgTunnelManagerTest { testApnName, false /*forceClose*/, mMockIwlanTunnelCallback, - mMockIwlanTunnelMetrics); + mMockIwlanTunnelMetrics, + BRINGDOWN_REASON_UNKNOWN); mTestLooper.dispatchAll(); verify(mMockIkeSession).close(); @@ -1153,6 +1361,7 @@ public class EpdgTunnelManagerTest { when(mMockTelephonyManager.createForSubscriptionId(DEFAULT_SUBID)) .thenReturn(mMockTelephonyManager); when(mMockCarrierConfigManager.getConfigForSubId(DEFAULT_SLOT_INDEX)).thenReturn(bundle); + when(mMockCarrierConfigManager.getConfigForSubId(anyInt(), anyString())).thenReturn(bundle); } private void setVariable(Object target, String variableName, Object value) throws Exception { @@ -2091,7 +2300,8 @@ public class EpdgTunnelManagerTest { TEST_APN_NAME, false /*forceClose*/, mMockIwlanTunnelCallback, - mMockIwlanTunnelMetrics); + mMockIwlanTunnelMetrics, + BRINGDOWN_REASON_UNKNOWN); mTestLooper.dispatchAll(); verify(mMockIwlanTunnelCallback, times(1)) |