Merge changes Iaafb2f9a,I90777d4c
* changes:
Retry IKE INIT if receiving Notify-Cookie
Support Cookie notification type
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 71d96ff..e35976b 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -2,11 +2,17 @@
"presubmit": [
{
"name": "FrameworksIkeTests"
+ },
+ {
+ "name": "CtsIkeTestCases"
}
],
"postsubmit": [
{
"name": "FrameworksIkeTests"
+ },
+ {
+ "name": "CtsIkeTestCases"
}
]
}
\ No newline at end of file
diff --git a/api/current.txt b/api/current.txt
index 6a1d8a1..b150294 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -63,6 +63,7 @@
method public void onClosedExceptionally(@NonNull android.net.ipsec.ike.exceptions.IkeException);
method public void onIpSecTransformCreated(@NonNull android.net.IpSecTransform, int);
method public void onIpSecTransformDeleted(@NonNull android.net.IpSecTransform, int);
+ method public default void onIpSecTransformsMigrated(@NonNull android.net.IpSecTransform, @NonNull android.net.IpSecTransform);
method public void onOpened(@NonNull android.net.ipsec.ike.ChildSessionConfiguration);
}
@@ -136,11 +137,14 @@
method public void finalize();
method public void kill();
method public void openChildSession(@NonNull android.net.ipsec.ike.ChildSessionParams, @NonNull android.net.ipsec.ike.ChildSessionCallback);
+ method public void setNetwork(@NonNull android.net.Network);
}
public interface IkeSessionCallback {
method public void onClosed();
method public void onClosedExceptionally(@NonNull android.net.ipsec.ike.exceptions.IkeException);
+ method public default void onError(@NonNull android.net.ipsec.ike.exceptions.IkeException);
+ method public default void onIkeSessionConnectionInfoChanged(@NonNull android.net.ipsec.ike.IkeSessionConnectionInfo);
method public void onOpened(@NonNull android.net.ipsec.ike.IkeSessionConfiguration);
}
@@ -176,6 +180,7 @@
method public boolean hasIkeOption(int);
field public static final int IKE_OPTION_ACCEPT_ANY_REMOTE_ID = 0; // 0x0
field public static final int IKE_OPTION_EAP_ONLY_AUTH = 1; // 0x1
+ field public static final int IKE_OPTION_MOBIKE = 2; // 0x2
}
public static final class IkeSessionParams.Builder {
@@ -348,11 +353,19 @@
public abstract class IkeException extends java.lang.Exception {
}
- public final class IkeInternalException extends android.net.ipsec.ike.exceptions.IkeException {
+ public final class IkeInternalException extends android.net.ipsec.ike.exceptions.IkeNonProtocolException {
ctor public IkeInternalException(@NonNull Throwable);
ctor public IkeInternalException(@NonNull String, @NonNull Throwable);
}
+ public final class IkeNetworkLostException extends android.net.ipsec.ike.exceptions.IkeNonProtocolException {
+ ctor public IkeNetworkLostException(@NonNull android.net.Network);
+ method @NonNull public android.net.Network getNetwork();
+ }
+
+ public abstract class IkeNonProtocolException extends android.net.ipsec.ike.exceptions.IkeException {
+ }
+
public abstract class IkeProtocolException extends android.net.ipsec.ike.exceptions.IkeException {
method public int getErrorType();
field public static final int ERROR_TYPE_AUTHENTICATION_FAILED = 24; // 0x18
diff --git a/api/system-current.txt b/api/system-current.txt
index 684c496..fd1f09e 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -15,7 +15,7 @@
package android.net.ipsec.ike {
public interface IkeSessionCallback {
- method public void onError(@NonNull android.net.ipsec.ike.exceptions.IkeProtocolException);
+ method @Deprecated public default void onError(@NonNull android.net.ipsec.ike.exceptions.IkeProtocolException);
}
public final class IkeSessionParams {
diff --git a/src/java/android/net/ipsec/ike/ChildSessionCallback.java b/src/java/android/net/ipsec/ike/ChildSessionCallback.java
index 9b67a00..1dd4530 100644
--- a/src/java/android/net/ipsec/ike/ChildSessionCallback.java
+++ b/src/java/android/net/ipsec/ike/ChildSessionCallback.java
@@ -108,7 +108,6 @@
* {@link IpSecManager#DIRECTION_IN}
* @param outIpSecTransform IpSecTransform to be used for traffic with {@link PolicyDirection}
* {@link IpSecManager#DIRECTION_OUT}
- * @hide
*/
default void onIpSecTransformsMigrated(
@NonNull IpSecTransform inIpSecTransform, @NonNull IpSecTransform outIpSecTransform) {}
diff --git a/src/java/android/net/ipsec/ike/IkeSession.java b/src/java/android/net/ipsec/ike/IkeSession.java
index cab99cc..5dab372 100644
--- a/src/java/android/net/ipsec/ike/IkeSession.java
+++ b/src/java/android/net/ipsec/ike/IkeSession.java
@@ -296,7 +296,6 @@
* @param network the Network to use for this IkeSession
* @throws IllegalStateException if MOBIKE is not configured in IkeSessionParams, MOBIKE is not
* active for this IkeSession, or if the Network was not specified in IkeSessionParams.
- * @hide
*/
public void setNetwork(@NonNull Network network) {
mIkeSessionStateMachine.setNetwork(network);
diff --git a/src/java/android/net/ipsec/ike/IkeSessionCallback.java b/src/java/android/net/ipsec/ike/IkeSessionCallback.java
index 21fac18..9468011 100644
--- a/src/java/android/net/ipsec/ike/IkeSessionCallback.java
+++ b/src/java/android/net/ipsec/ike/IkeSessionCallback.java
@@ -67,12 +67,13 @@
* INVALID_MESSAGE_ID.
*
* @param exception the detailed error information.
+ * @deprecated Implementers should override {@link #onError(IkeException)} to handle {@link
+ * IkeProtocolException}s instead of using this method.
* @hide
*/
- // TODO: b/158033037 Deprecate this method and add a public API that takes an IkeException when
- // exposing MOBIKE APIs
@SystemApi
- void onError(@NonNull IkeProtocolException exception);
+ @Deprecated
+ default void onError(@NonNull IkeProtocolException exception) {}
/**
* Called if a recoverable error is encountered in an established {@link IkeSession}.
@@ -81,7 +82,6 @@
* non-protocol errors such as the underlying {@link android.net.Network} dying.
*
* @param exception the detailed error information.
- * @hide
*/
default void onError(@NonNull IkeException exception) {
if (exception instanceof IkeProtocolException) {
@@ -108,7 +108,6 @@
* </ul>
*
* @param connectionInfo the updated IkeSessionConnectionInfo for the Session.
- * @hide
*/
default void onIkeSessionConnectionInfoChanged(
@NonNull IkeSessionConnectionInfo connectionInfo) {}
diff --git a/src/java/android/net/ipsec/ike/IkeSessionParams.java b/src/java/android/net/ipsec/ike/IkeSessionParams.java
index b093219..d2482e3 100644
--- a/src/java/android/net/ipsec/ike/IkeSessionParams.java
+++ b/src/java/android/net/ipsec/ike/IkeSessionParams.java
@@ -117,27 +117,39 @@
/**
* If set, the IKE library will attempt to enable MOBIKE for the resulting IKE Session.
*
+ * <p>To support MOBIKE, callers must implement:
+ *
+ * <ul>
+ * <li>{@link IkeSessionCallback#onIkeSessionConnectionInfoChanged(IkeSessionConnectionInfo)}:
+ * this MUST migrate all IpSecTunnelInterface instances associated with this IkeSession.
+ * <li>{@link ChildSessionCallback#onIpSecTransformsMigrated(android.net.IpSecTransform,
+ * android.net.IpSecTransform)}: this MUST re-apply the migrated transforms to the
+ * IpSecTunnelInterface associated with this ChildSessionCallback, via {@link
+ * android.net.IpSecManager#applyTunnelModeTransform(
+ * android.net.IpSecManager.IpSecTunnelInterface, int, android.net.IpSecTransform)}.
+ * </ul>
+ *
* <p>MOBIKE support is compatible with two Network modes:
*
* <ul>
* <li><b>Caller managed:</b> The caller controls the underlying Network for the IKE Session
* at all times. The IKE Session will only change underlying Networks if the caller
* initiates it through {@link IkeSession#setNetwork(Network)}. If the caller-specified
- * Network dies, they will be notified via {@link
+ * Network is lost, they will be notified via {@link
* IkeSessionCallback#onError(android.net.ipsec.ike.exceptions.IkeException)} with an
- * {@link android.net.ipsec.ike.exceptions.IkeNetworkDiedException} specifying the Network
- * that died.
- * <li><b>Platform Default:</b> The IKE Session will always track the Platform default
- * Network. The IKE Session will start on the Platform default Network, and any subsequent
- * changes to the default Network (after the IKE_AUTH exchange completes) will cause the
- * IKE Session's underlying Network to change. If the default Network dies with no
- * replacements, the caller will be notified via {@link
+ * {@link android.net.ipsec.ike.exceptions.IkeNetworkLostException} specifying the Network
+ * that was lost.
+ * <li><b>Platform Default:</b> The IKE Session will always track the application default
+ * Network. The IKE Session will start on the application default Network, and any
+ * subsequent changes to the default Network (after the IKE_AUTH exchange completes) will
+ * cause the IKE Session's underlying Network to change. If the default Network is lost
+ * with no replacements, the caller will be notified via {@link
* IkeSessionCallback#onError(android.net.ipsec.ike.exceptions.IkeException)} with an
- * {@link android.net.ipsec.ike.exceptions.IkeNetworkDiedException}. The caller can either
+ * {@link android.net.ipsec.ike.exceptions.IkeNetworkLostException}. The caller can either
* wait until for a new default Network to become available or they may close the Session
* manually via {@link IkeSession#close()}. Note that the IKE Session's maximum
* retransmissions may expire while waiting for a new default Network, in which case the
- * Session will automatically close
+ * Session will automatically close.
* </ul>
*
* <p>Use of MOBIKE in the IKE Session requires the peer to also support MOBIKE.
@@ -147,9 +159,8 @@
*
* <p>Checking for MOBIKE use in an IKE Session is done via {@link
* IkeSessionConfiguration#isIkeExtensionEnabled(int)}.
- *
- * @hide
*/
+ // TODO(b/175416035): update docs to @link to API for migrating IpSecTunnelInterfaces
public static final int IKE_OPTION_MOBIKE = 2;
private static final int MIN_IKE_OPTION = IKE_OPTION_ACCEPT_ANY_REMOTE_ID;
diff --git a/src/java/android/net/ipsec/ike/exceptions/IkeInternalException.java b/src/java/android/net/ipsec/ike/exceptions/IkeInternalException.java
index aaa69e4..37f7293 100644
--- a/src/java/android/net/ipsec/ike/exceptions/IkeInternalException.java
+++ b/src/java/android/net/ipsec/ike/exceptions/IkeInternalException.java
@@ -23,7 +23,7 @@
* <p>Causes may include exceptions such as {@link IpSecManager.SpiUnavailableException} when the
* requested SPI resources failed to be allocated.
*/
-public final class IkeInternalException extends IkeException {
+public final class IkeInternalException extends IkeNonProtocolException {
/**
* Constructs a new exception with the specified cause.
*
diff --git a/src/java/android/net/ipsec/ike/exceptions/IkeNetworkDiedException.java b/src/java/android/net/ipsec/ike/exceptions/IkeNetworkLostException.java
similarity index 75%
rename from src/java/android/net/ipsec/ike/exceptions/IkeNetworkDiedException.java
rename to src/java/android/net/ipsec/ike/exceptions/IkeNetworkLostException.java
index 5fdae70..d638502 100644
--- a/src/java/android/net/ipsec/ike/exceptions/IkeNetworkDiedException.java
+++ b/src/java/android/net/ipsec/ike/exceptions/IkeNetworkLostException.java
@@ -16,15 +16,20 @@
package android.net.ipsec.ike.exceptions;
+import android.annotation.NonNull;
import android.net.Network;
import android.net.ipsec.ike.IkeSessionCallback;
import java.util.Objects;
/**
- * IkeNetworkDiedException is returned to the caller via {@link
+ * IkeNetworkLostException is returned to the caller via {@link
* IkeSessionCallback#onError(IkeException)} if the underlying Network for the {@link IkeSession}
- * dies with no alternatives.
+ * was lost with no alternatives.
+ *
+ * <p>This Exception corresponds to {@link
+ * android.net.ConnectivityManager.NetworkCallback#onLost(android.net.Network)} being invoked for
+ * the specified underlying Network.
*
* <p>When the caller receives this Exception, they must either:
*
@@ -40,21 +45,20 @@
* </ul>
* <li>close the corresponding IkeSession.
* </ul>
- *
- * @hide
*/
-public final class IkeNetworkDiedException extends IkeNonProtocolException {
+public final class IkeNetworkLostException extends IkeNonProtocolException {
private final Network mNetwork;
- /** Constructs an IkeNetworkDiedException to indicate the specified Network died. */
- public IkeNetworkDiedException(Network network) {
+ /** Constructs an IkeNetworkLostException to indicate the specified Network was lost. */
+ public IkeNetworkLostException(@NonNull Network network) {
super();
Objects.requireNonNull(network, "network is null");
mNetwork = network;
}
- /** Returns the IkeSession's underlying Network that died. */
+ /** Returns the IkeSession's underlying Network that was lost. */
+ @NonNull
public Network getNetwork() {
return mNetwork;
}
diff --git a/src/java/android/net/ipsec/ike/exceptions/IkeNonProtocolException.java b/src/java/android/net/ipsec/ike/exceptions/IkeNonProtocolException.java
index d8a3162..f005504 100644
--- a/src/java/android/net/ipsec/ike/exceptions/IkeNonProtocolException.java
+++ b/src/java/android/net/ipsec/ike/exceptions/IkeNonProtocolException.java
@@ -18,8 +18,6 @@
/**
* IkeNonProtocolException encapsulates all implementation-specific non-protocol IKE errors.
- *
- * @hide
*/
public abstract class IkeNonProtocolException extends IkeException {
/** @hide */
diff --git a/src/java/com/android/internal/net/ipsec/ike/IkeSessionStateMachine.java b/src/java/com/android/internal/net/ipsec/ike/IkeSessionStateMachine.java
index 6deac8d..c3c648d 100644
--- a/src/java/com/android/internal/net/ipsec/ike/IkeSessionStateMachine.java
+++ b/src/java/com/android/internal/net/ipsec/ike/IkeSessionStateMachine.java
@@ -69,6 +69,7 @@
import android.net.IpSecManager.ResourceUnavailableException;
import android.net.IpSecManager.SpiUnavailableException;
import android.net.IpSecManager.UdpEncapsulationSocket;
+import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
@@ -87,7 +88,7 @@
import android.net.ipsec.ike.exceptions.AuthenticationFailedException;
import android.net.ipsec.ike.exceptions.IkeException;
import android.net.ipsec.ike.exceptions.IkeInternalException;
-import android.net.ipsec.ike.exceptions.IkeNetworkDiedException;
+import android.net.ipsec.ike.exceptions.IkeNetworkLostException;
import android.net.ipsec.ike.exceptions.IkeProtocolException;
import android.net.ipsec.ike.exceptions.InvalidKeException;
import android.net.ipsec.ike.exceptions.InvalidSyntaxException;
@@ -162,6 +163,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.net.Inet4Address;
+import java.net.Inet6Address;
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.security.GeneralSecurityException;
@@ -435,6 +437,11 @@
/** Local port assigned on device. Initialized in Initial State. */
@VisibleForTesting int mLocalPort;
+ /** Available remote addresses that are v4. Resolved in Initial State. */
+ @VisibleForTesting final List<Inet4Address> mRemoteAddressesV4 = new ArrayList<>();
+ /** Available remote addresses that are v6. Resolved in Initial State. */
+ @VisibleForTesting final List<Inet6Address> mRemoteAddressesV6 = new ArrayList<>();
+
/** Indicates if both sides support NAT traversal. Set in IKE INIT. */
@VisibleForTesting boolean mSupportNatTraversal;
/** Indicates if local node is behind a NAT. */
@@ -1204,9 +1211,21 @@
@Override
public void enterState() {
try {
- // TODO(b/149954916): Do DNS resolution asynchronously and support resolving
- // multiple addresses.
- mRemoteAddress = mNetwork.getByName(mIkeSessionParams.getServerHostname());
+ // TODO(b/149954916): Do DNS resolution asynchronously
+ InetAddress[] allRemoteAddresses =
+ mNetwork.getAllByName(mIkeSessionParams.getServerHostname());
+
+ logd("Resolved addresses for peer: " + Arrays.toString(allRemoteAddresses));
+
+ for (InetAddress remoteAddress : allRemoteAddresses) {
+ if (remoteAddress instanceof Inet4Address) {
+ mRemoteAddressesV4.add((Inet4Address) remoteAddress);
+ } else {
+ mRemoteAddressesV6.add((Inet6Address) remoteAddress);
+ }
+ }
+
+ setRemoteAddress();
boolean isIpv4 = mRemoteAddress instanceof Inet4Address;
if (isIpv4) {
@@ -1244,6 +1263,33 @@
}
/**
+ * Set the remote address for the peer.
+ *
+ * <p>Prefers IPv6 addresses if:
+ *
+ * <ul>
+ * <li>an IPv6 address is known for the peer, and
+ * <li>the current underlying Network has a global (non-link local) IPv6 address available
+ * </ul>
+ *
+ * Otherwise, an IPv4 address will be used.
+ */
+ private void setRemoteAddress() {
+ LinkProperties linkProperties = mConnectivityManager.getLinkProperties(mNetwork);
+ if (!mRemoteAddressesV6.isEmpty() && linkProperties.hasGlobalIpv6Address()) {
+ // TODO(b/175348096): randomly choose from available addresses
+ mRemoteAddress = mRemoteAddressesV6.get(0);
+ } else {
+ if (mRemoteAddressesV4.isEmpty()) {
+ throw new IllegalArgumentException("No valid IPv4 or IPv6 addresses for peer");
+ }
+
+ // TODO(b/175348096): randomly choose from available addresses
+ mRemoteAddress = mRemoteAddressesV4.get(0);
+ }
+ }
+
+ /**
* Idle represents a state when there is no ongoing IKE exchange affecting established IKE SA.
*/
class Idle extends LocalRequestQueuer {
@@ -5469,11 +5515,13 @@
throw new IllegalStateException("MOBIKE must be enabled to update the Network");
}
- // TODO(b/172060298): prefer IPv6 once Responder addresses are cached
- boolean isIpv4 = mRemoteAddress instanceof Inet4Address;
Network oldNetwork = mNetwork;
mNetwork = network;
+ setRemoteAddress();
+
+ boolean isIpv4 = mRemoteAddress instanceof Inet4Address;
+
try {
// Only switch the IkeSocket if the underlying Network actually changes. This may not
// always happen (ex: the underlying Network loses the current local address)
@@ -5529,6 +5577,6 @@
@Override
public void onUnderlyingNetworkDied() {
executeUserCallback(
- () -> mIkeSessionCallback.onError(new IkeNetworkDiedException(mNetwork)));
+ () -> mIkeSessionCallback.onError(new IkeNetworkLostException(mNetwork)));
}
}
diff --git a/src/java/com/android/internal/net/ipsec/ike/net/IkeDefaultNetworkCallback.java b/src/java/com/android/internal/net/ipsec/ike/net/IkeDefaultNetworkCallback.java
index f3c7fa0..fa4c6bf 100644
--- a/src/java/com/android/internal/net/ipsec/ike/net/IkeDefaultNetworkCallback.java
+++ b/src/java/com/android/internal/net/ipsec/ike/net/IkeDefaultNetworkCallback.java
@@ -21,7 +21,7 @@
import java.net.InetAddress;
/**
- * IkeDefaultNetworkCallback is a network callback used to track the platform's default network.
+ * IkeDefaultNetworkCallback is a network callback used to track the application default Network.
*
* <p>This NetworkCallback will notify IkeSessionStateMachine if:
*
@@ -47,7 +47,7 @@
return;
}
- logd("Platform default Network changed to " + network);
+ logd("Application default Network changed to " + network);
mIkeNetworkUpdater.onUnderlyingNetworkUpdated(network);
}
}
diff --git a/tests/cts/src/android/ipsec/ike/cts/SaProposalTest.java b/tests/cts/src/android/ipsec/ike/cts/SaProposalTest.java
index e58a3fe..0b8bfca 100644
--- a/tests/cts/src/android/ipsec/ike/cts/SaProposalTest.java
+++ b/tests/cts/src/android/ipsec/ike/cts/SaProposalTest.java
@@ -59,28 +59,54 @@
@RunWith(AndroidJUnit4.class)
public class SaProposalTest {
- private static final List<Pair<Integer, Integer>> NORMAL_MODE_CIPHERS = new ArrayList<>();
- private static final List<Pair<Integer, Integer>> COMBINED_MODE_CIPHERS = new ArrayList<>();
- private static final List<Integer> INTEGRITY_ALGOS = new ArrayList<>();
+ private static final List<Pair<Integer, Integer>> IKE_NORMAL_MODE_CIPHERS = new ArrayList<>();
+ private static final List<Pair<Integer, Integer>> IKE_COMBINED_MODE_CIPHERS = new ArrayList<>();
+ private static final List<Integer> IKE_INTEGRITY_ALGOS = new ArrayList<>();
+ private static final List<Pair<Integer, Integer>> CHILD_NORMAL_MODE_CIPHERS = new ArrayList<>();
+ private static final List<Pair<Integer, Integer>> CHILD_COMBINED_MODE_CIPHERS =
+ new ArrayList<>();
+ private static final List<Integer> CHILD_INTEGRITY_ALGOS = new ArrayList<>();
private static final List<Integer> DH_GROUPS = new ArrayList<>();
private static final List<Integer> DH_GROUPS_WITH_NONE = new ArrayList<>();
private static final List<Integer> PRFS = new ArrayList<>();
static {
- NORMAL_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_3DES, KEY_LEN_UNUSED));
- NORMAL_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_128));
- NORMAL_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_192));
- NORMAL_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_256));
+ IKE_NORMAL_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_3DES, KEY_LEN_UNUSED));
+ IKE_NORMAL_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_128));
+ IKE_NORMAL_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_192));
+ IKE_NORMAL_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_256));
- COMBINED_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_GCM_8, KEY_LEN_AES_128));
- COMBINED_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_GCM_12, KEY_LEN_AES_192));
- COMBINED_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_GCM_16, KEY_LEN_AES_256));
+ for (Pair<Integer, Integer> pair : IKE_NORMAL_MODE_CIPHERS) {
+ // TODO: b/1522448 Check against ChildSaProposal#getSupportedEncryptionAlgorithms
+ // when it is exposed
+ if (pair.first != ENCRYPTION_ALGORITHM_3DES) {
+ CHILD_NORMAL_MODE_CIPHERS.add(pair);
+ }
+ }
- INTEGRITY_ALGOS.add(INTEGRITY_ALGORITHM_HMAC_SHA1_96);
- INTEGRITY_ALGOS.add(INTEGRITY_ALGORITHM_AES_XCBC_96);
- INTEGRITY_ALGOS.add(INTEGRITY_ALGORITHM_HMAC_SHA2_256_128);
- INTEGRITY_ALGOS.add(INTEGRITY_ALGORITHM_HMAC_SHA2_384_192);
- INTEGRITY_ALGOS.add(INTEGRITY_ALGORITHM_HMAC_SHA2_512_256);
+ IKE_COMBINED_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_GCM_8, KEY_LEN_AES_128));
+ IKE_COMBINED_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_GCM_12, KEY_LEN_AES_192));
+ IKE_COMBINED_MODE_CIPHERS.add(new Pair<>(ENCRYPTION_ALGORITHM_AES_GCM_16, KEY_LEN_AES_256));
+
+ for (Pair<Integer, Integer> pair : IKE_COMBINED_MODE_CIPHERS) {
+ // TODO: b/1522448 Add ChaChaPoly in IKE_COMBINED_MODE_CIPHERS and check against
+ // ChildSaProposal#getSupportedEncryptionAlgorithms when it is exposed
+ CHILD_COMBINED_MODE_CIPHERS.add(pair);
+ }
+
+ IKE_INTEGRITY_ALGOS.add(INTEGRITY_ALGORITHM_HMAC_SHA1_96);
+ IKE_INTEGRITY_ALGOS.add(INTEGRITY_ALGORITHM_AES_XCBC_96);
+ IKE_INTEGRITY_ALGOS.add(INTEGRITY_ALGORITHM_HMAC_SHA2_256_128);
+ IKE_INTEGRITY_ALGOS.add(INTEGRITY_ALGORITHM_HMAC_SHA2_384_192);
+ IKE_INTEGRITY_ALGOS.add(INTEGRITY_ALGORITHM_HMAC_SHA2_512_256);
+
+ for (Integer algo : IKE_INTEGRITY_ALGOS) {
+ // TODO: b/1522448 Check against ChildSaProposal#getSupportedIntegrityAlgorithms
+ // when it is exposed
+ if (algo != INTEGRITY_ALGORITHM_AES_XCBC_96) {
+ CHILD_INTEGRITY_ALGOS.add(algo);
+ }
+ }
DH_GROUPS.add(DH_GROUP_1024_BIT_MODP);
DH_GROUPS.add(DH_GROUP_2048_BIT_MODP);
@@ -97,7 +123,7 @@
// Package private
static IkeSaProposal buildIkeSaProposalWithNormalModeCipher() {
- return buildIkeSaProposal(NORMAL_MODE_CIPHERS, INTEGRITY_ALGOS, PRFS, DH_GROUPS);
+ return buildIkeSaProposal(IKE_NORMAL_MODE_CIPHERS, IKE_INTEGRITY_ALGOS, PRFS, DH_GROUPS);
}
// Package private
@@ -111,7 +137,7 @@
if (hasIntegrityNone) {
integerAlgos.add(INTEGRITY_ALGORITHM_NONE);
}
- return buildIkeSaProposal(COMBINED_MODE_CIPHERS, integerAlgos, PRFS, DH_GROUPS);
+ return buildIkeSaProposal(IKE_COMBINED_MODE_CIPHERS, integerAlgos, PRFS, DH_GROUPS);
}
private static IkeSaProposal buildIkeSaProposal(
@@ -139,7 +165,8 @@
// Package private
static ChildSaProposal buildChildSaProposalWithNormalModeCipher() {
- return buildChildSaProposal(NORMAL_MODE_CIPHERS, INTEGRITY_ALGOS, DH_GROUPS_WITH_NONE);
+ return buildChildSaProposal(
+ CHILD_NORMAL_MODE_CIPHERS, CHILD_INTEGRITY_ALGOS, DH_GROUPS_WITH_NONE);
}
// Package private
@@ -154,7 +181,7 @@
integerAlgos.add(INTEGRITY_ALGORITHM_NONE);
}
- return buildChildSaProposal(COMBINED_MODE_CIPHERS, integerAlgos, DH_GROUPS_WITH_NONE);
+ return buildChildSaProposal(CHILD_COMBINED_MODE_CIPHERS, integerAlgos, DH_GROUPS_WITH_NONE);
}
private static ChildSaProposal buildChildSaProposal(
@@ -179,15 +206,15 @@
// Package private
static ChildSaProposal buildChildSaProposalWithOnlyCiphers() {
return buildChildSaProposal(
- COMBINED_MODE_CIPHERS, Collections.EMPTY_LIST, Collections.EMPTY_LIST);
+ CHILD_COMBINED_MODE_CIPHERS, Collections.EMPTY_LIST, Collections.EMPTY_LIST);
}
@Test
public void testBuildIkeSaProposalWithNormalModeCipher() {
IkeSaProposal saProposal = buildIkeSaProposalWithNormalModeCipher();
- assertEquals(NORMAL_MODE_CIPHERS, saProposal.getEncryptionAlgorithms());
- assertEquals(INTEGRITY_ALGOS, saProposal.getIntegrityAlgorithms());
+ assertEquals(IKE_NORMAL_MODE_CIPHERS, saProposal.getEncryptionAlgorithms());
+ assertEquals(IKE_INTEGRITY_ALGOS, saProposal.getIntegrityAlgorithms());
assertEquals(PRFS, saProposal.getPseudorandomFunctions());
assertEquals(DH_GROUPS, saProposal.getDhGroups());
}
@@ -197,7 +224,7 @@
IkeSaProposal saProposal =
buildIkeSaProposalWithCombinedModeCipher(false /* hasIntegrityNone */);
- assertEquals(COMBINED_MODE_CIPHERS, saProposal.getEncryptionAlgorithms());
+ assertEquals(IKE_COMBINED_MODE_CIPHERS, saProposal.getEncryptionAlgorithms());
assertEquals(PRFS, saProposal.getPseudorandomFunctions());
assertEquals(DH_GROUPS, saProposal.getDhGroups());
assertTrue(saProposal.getIntegrityAlgorithms().isEmpty());
@@ -208,7 +235,7 @@
IkeSaProposal saProposal =
buildIkeSaProposalWithCombinedModeCipher(true /* hasIntegrityNone */);
- assertEquals(COMBINED_MODE_CIPHERS, saProposal.getEncryptionAlgorithms());
+ assertEquals(IKE_COMBINED_MODE_CIPHERS, saProposal.getEncryptionAlgorithms());
assertEquals(PRFS, saProposal.getPseudorandomFunctions());
assertEquals(DH_GROUPS, saProposal.getDhGroups());
assertEquals(Arrays.asList(INTEGRITY_ALGORITHM_NONE), saProposal.getIntegrityAlgorithms());
@@ -218,8 +245,8 @@
public void testBuildChildSaProposalWithNormalModeCipher() {
ChildSaProposal saProposal = buildChildSaProposalWithNormalModeCipher();
- assertEquals(NORMAL_MODE_CIPHERS, saProposal.getEncryptionAlgorithms());
- assertEquals(INTEGRITY_ALGOS, saProposal.getIntegrityAlgorithms());
+ assertEquals(CHILD_NORMAL_MODE_CIPHERS, saProposal.getEncryptionAlgorithms());
+ assertEquals(CHILD_INTEGRITY_ALGOS, saProposal.getIntegrityAlgorithms());
assertEquals(DH_GROUPS_WITH_NONE, saProposal.getDhGroups());
}
@@ -228,7 +255,7 @@
ChildSaProposal saProposal =
buildChildSaProposalWithCombinedModeCipher(false /* hasIntegrityNone */);
- assertEquals(COMBINED_MODE_CIPHERS, saProposal.getEncryptionAlgorithms());
+ assertEquals(CHILD_COMBINED_MODE_CIPHERS, saProposal.getEncryptionAlgorithms());
assertTrue(saProposal.getIntegrityAlgorithms().isEmpty());
assertEquals(DH_GROUPS_WITH_NONE, saProposal.getDhGroups());
}
@@ -238,7 +265,7 @@
ChildSaProposal saProposal =
buildChildSaProposalWithCombinedModeCipher(true /* hasIntegrityNone */);
- assertEquals(COMBINED_MODE_CIPHERS, saProposal.getEncryptionAlgorithms());
+ assertEquals(CHILD_COMBINED_MODE_CIPHERS, saProposal.getEncryptionAlgorithms());
assertEquals(Arrays.asList(INTEGRITY_ALGORITHM_NONE), saProposal.getIntegrityAlgorithms());
assertEquals(DH_GROUPS_WITH_NONE, saProposal.getDhGroups());
}
@@ -247,7 +274,7 @@
public void testBuildChildSaProposalWithOnlyCiphers() {
ChildSaProposal saProposal = buildChildSaProposalWithOnlyCiphers();
- assertEquals(COMBINED_MODE_CIPHERS, saProposal.getEncryptionAlgorithms());
+ assertEquals(CHILD_COMBINED_MODE_CIPHERS, saProposal.getEncryptionAlgorithms());
assertTrue(saProposal.getIntegrityAlgorithms().isEmpty());
assertTrue(saProposal.getDhGroups().isEmpty());
}
diff --git a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/IkeSessionStateMachineTest.java b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/IkeSessionStateMachineTest.java
index 90986a6..528bbe2 100644
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/IkeSessionStateMachineTest.java
+++ b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/IkeSessionStateMachineTest.java
@@ -97,6 +97,8 @@
import android.annotation.Nullable;
import android.app.AlarmManager;
import android.content.Context;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
import android.net.Network;
import android.net.eap.EapSessionConfig;
import android.net.ipsec.ike.ChildSaProposal;
@@ -117,7 +119,7 @@
import android.net.ipsec.ike.exceptions.AuthenticationFailedException;
import android.net.ipsec.ike.exceptions.IkeException;
import android.net.ipsec.ike.exceptions.IkeInternalException;
-import android.net.ipsec.ike.exceptions.IkeNetworkDiedException;
+import android.net.ipsec.ike.exceptions.IkeNetworkLostException;
import android.net.ipsec.ike.exceptions.IkeProtocolException;
import android.net.ipsec.ike.exceptions.InvalidSyntaxException;
import android.net.ipsec.ike.exceptions.NoValidProposalChosenException;
@@ -204,6 +206,7 @@
import java.io.IOException;
import java.net.Inet4Address;
+import java.net.Inet6Address;
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.security.GeneralSecurityException;
@@ -362,6 +365,8 @@
private IkeUdp6Socket mSpyIkeUdp6Socket;
private IkeSocket mSpyCurrentIkeSocket;
+ private LinkAddress mMockLinkAddressGlobalV6;
+
private IkeNattKeepalive mMockIkeNattKeepalive;
private TestLooper mLooper;
@@ -766,6 +771,10 @@
eq(mMockDefaultNetwork), eq(false /* isIpv4 */), any(), anyInt()))
.thenReturn(LOCAL_ADDRESS_V6);
+ mMockLinkAddressGlobalV6 = mock(LinkAddress.class);
+ when(mMockLinkAddressGlobalV6.getAddress()).thenReturn(UPDATED_LOCAL_ADDRESS_V6);
+ when(mMockLinkAddressGlobalV6.isGlobalPreferred()).thenReturn(true);
+
mMockEapAuthenticatorFactory = mock(IkeEapAuthenticatorFactory.class);
mMockEapAuthenticator = mock(EapAuthenticator.class);
doReturn(mMockEapAuthenticator)
@@ -1419,7 +1428,7 @@
.build();
mIkeSessionStateMachine = makeAndStartIkeSession(ikeParams);
- verify(mMockDefaultNetwork).getByName(REMOTE_HOSTNAME);
+ verify(mMockDefaultNetwork).getAllByName(REMOTE_HOSTNAME);
}
@Test
@@ -4839,7 +4848,6 @@
IkeSessionParams mockSessionParams = mock(IkeSessionParams.class);
when(mockSessionParams.getServerHostname()).thenReturn(REMOTE_HOSTNAME);
- when(mMockDefaultNetwork.getByName(REMOTE_HOSTNAME)).thenReturn(REMOTE_ADDRESS);
RuntimeException cause = new RuntimeException();
when(mockSessionParams.getSaProposalsInternal()).thenThrow(cause);
@@ -5462,8 +5470,15 @@
// IKE client always supports NAT-T. So the peer decides if both sides support NAT-T.
mIkeSessionStateMachine.mSupportNatTraversal = doesPeerSupportNatt;
- mIkeSessionStateMachine.mLocalAddress = isIpv4 ? LOCAL_ADDRESS : LOCAL_ADDRESS_V6;
- mIkeSessionStateMachine.mRemoteAddress = isIpv4 ? REMOTE_ADDRESS : REMOTE_ADDRESS_V6;
+ if (isIpv4) {
+ mIkeSessionStateMachine.mLocalAddress = LOCAL_ADDRESS;
+ mIkeSessionStateMachine.mRemoteAddress = REMOTE_ADDRESS;
+ mIkeSessionStateMachine.mRemoteAddressesV4.add(REMOTE_ADDRESS);
+ } else {
+ mIkeSessionStateMachine.mLocalAddress = LOCAL_ADDRESS_V6;
+ mIkeSessionStateMachine.mRemoteAddress = REMOTE_ADDRESS_V6;
+ mIkeSessionStateMachine.mRemoteAddressesV6.add(REMOTE_ADDRESS_V6);
+ }
if (doesPeerSupportNatt && isIpv4) {
// Assume NATs are detected on both sides
@@ -5613,7 +5628,7 @@
ArgumentCaptor<IkeException> exceptionCaptor = ArgumentCaptor.forClass(IkeException.class);
verify(mMockIkeSessionCallback).onError(exceptionCaptor.capture());
- IkeNetworkDiedException cause = (IkeNetworkDiedException) exceptionCaptor.getValue();
+ IkeNetworkLostException cause = (IkeNetworkLostException) exceptionCaptor.getValue();
assertEquals(mMockDefaultNetwork, cause.getNetwork());
}
@@ -5635,9 +5650,23 @@
private Network mockNewNetworkAndAddress(boolean isIpv4) throws Exception {
Network newNetwork = mock(Network.class);
- InetAddress expectedRemoteAddress = isIpv4 ? REMOTE_ADDRESS : REMOTE_ADDRESS_V6;
- InetAddress injectedLocalAddress =
- isIpv4 ? UPDATED_LOCAL_ADDRESS : UPDATED_LOCAL_ADDRESS_V6;
+ InetAddress expectedRemoteAddress;
+ InetAddress injectedLocalAddress;
+ if (isIpv4) {
+ expectedRemoteAddress = REMOTE_ADDRESS;
+ injectedLocalAddress = UPDATED_LOCAL_ADDRESS;
+
+ mIkeSessionStateMachine.mRemoteAddressesV4.add((Inet4Address) expectedRemoteAddress);
+ } else {
+ expectedRemoteAddress = REMOTE_ADDRESS_V6;
+ injectedLocalAddress = UPDATED_LOCAL_ADDRESS_V6;
+ mIkeSessionStateMachine.mRemoteAddressesV6.add((Inet6Address) expectedRemoteAddress);
+
+ LinkProperties linkProperties = new LinkProperties();
+ linkProperties.addLinkAddress(mMockLinkAddressGlobalV6);
+ when(mMockConnectManager.getLinkProperties(eq(newNetwork))).thenReturn(linkProperties);
+ }
+
when(mMockIkeLocalAddressGenerator.generateLocalAddress(
eq(newNetwork), eq(isIpv4), eq(expectedRemoteAddress), anyInt()))
.thenReturn(injectedLocalAddress);
diff --git a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/IkeSessionTestBase.java b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/IkeSessionTestBase.java
index 5d14a04..7528c4c 100644
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/IkeSessionTestBase.java
+++ b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/IkeSessionTestBase.java
@@ -50,6 +50,7 @@
import java.net.Inet4Address;
import java.net.Inet6Address;
+import java.net.InetAddress;
import java.util.concurrent.Executor;
public abstract class IkeSessionTestBase {
@@ -109,10 +110,12 @@
.newWakeLock(anyInt(), argThat(tag -> tag.contains(LOCAL_REQUEST_WAKE_LOCK_TAG)));
mMockDefaultNetwork = mock(Network.class);
- doReturn(REMOTE_ADDRESS).when(mMockDefaultNetwork).getByName(REMOTE_HOSTNAME);
- doReturn(REMOTE_ADDRESS)
+ doReturn(new InetAddress[] {REMOTE_ADDRESS})
.when(mMockDefaultNetwork)
- .getByName(REMOTE_ADDRESS.getHostAddress());
+ .getAllByName(REMOTE_HOSTNAME);
+ doReturn(new InetAddress[] {REMOTE_ADDRESS})
+ .when(mMockDefaultNetwork)
+ .getAllByName(REMOTE_ADDRESS.getHostAddress());
mMockSocketKeepalive = mock(SocketKeepalive.class);