Defer incoming requests in IKE_AUTH states
This change defers incoming IKE requests during authentication. This
could be a result of network packets racing, and is perfectly valid. As
such, they should be deferred to the next (Idle) state.
Bug: 139482382
Test: FrameworksIkeTests passing
Change-Id: Ia9ed9c60fde32b0a0af1ba0225772b4d632cfea7
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 2e5e8f5..60d18b9 100644
--- a/src/java/com/android/internal/net/ipsec/ike/IkeSessionStateMachine.java
+++ b/src/java/com/android/internal/net/ipsec/ike/IkeSessionStateMachine.java
@@ -3048,6 +3048,19 @@
// TODO: b/139482382 If receiving a remote request while waiting for the last IKE AUTH
// response, defer it to next state.
+ @Override
+ protected void handleRequestIkeMessage(
+ IkeMessage ikeMessage, int ikeExchangeSubType, Message message) {
+ IkeSaRecord ikeSaRecord = getIkeSaRecordForPacket(ikeMessage.ikeHeader);
+
+ // Null out last received packet, so the next state (that handles the actual request)
+ // does not treat the message as a retransmission.
+ ikeSaRecord.updateLastReceivedReqFirstPacket(null);
+
+ // Send to next state; we can't handle this yet.
+ deferMessage(message);
+ }
+
protected IkeMessage buildIkeAuthReqMessage(List<IkePayload> payloadList) {
// Build IKE header
IkeHeader ikeHeader =
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 73b6c7e..e382328 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
@@ -169,6 +169,7 @@
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.Arrays;
+import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Executor;
@@ -2317,6 +2318,61 @@
IkePayload.PAYLOAD_TYPE_ID_RESPONDER, true /*isResp*/, idRespPayloadHex);
}
+ private void verifyEmptyInformationalSent(int count) {
+ verify(mMockIkeMessageHelper, times(count))
+ .encryptAndEncode(
+ anyObject(),
+ anyObject(),
+ eq(mSpyCurrentIkeSaRecord),
+ argThat(
+ msg -> {
+ return msg.ikePayloadList.isEmpty()
+ && msg.ikeHeader.isResponseMsg
+ && msg.ikeHeader.fromIkeInitiator
+ && msg.ikeHeader.exchangeType
+ == IkeHeader.EXCHANGE_TYPE_INFORMATIONAL;
+ }),
+ anyBoolean(),
+ anyInt());
+ }
+
+ @Test
+ public void testCreateIkeLocalIkeAuthDefersOtherMessages() throws Exception {
+ mockIkeInitAndTransitionToIkeAuth(mIkeSessionStateMachine.mCreateIkeLocalIkeAuth);
+ verifyRetransmissionStarted();
+
+ // Build IKE AUTH response with Auth-PSK, ID-Responder and config payloads.
+ List<IkePayload> authRelatedPayloads = new LinkedList<>();
+ IkeAuthPskPayload spyAuthPayload = makeSpyRespPskPayload();
+ authRelatedPayloads.add(spyAuthPayload);
+
+ ReceivedIkePacket req =
+ makeDummyEncryptedReceivedIkePacket(
+ mSpyCurrentIkeSaRecord,
+ IkeHeader.EXCHANGE_TYPE_INFORMATIONAL,
+ false,
+ Collections.emptyList(),
+ Collections.emptyList());
+ mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, req);
+
+ verifyEmptyInformationalSent(0);
+
+ // Send IKE AUTH response to IKE state machine to trigger moving to next state
+ IkeIdPayload respIdPayload = makeRespIdPayload();
+ authRelatedPayloads.add(respIdPayload);
+ authRelatedPayloads.add(makeConfigPayload());
+
+ ReceivedIkePacket authResp = makeIkeAuthRespWithChildPayloads(authRelatedPayloads);
+ mIkeSessionStateMachine.sendMessage(
+ IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, authResp);
+ mLooper.dispatchAll();
+
+ verifyEmptyInformationalSent(1);
+ assertTrue(
+ mIkeSessionStateMachine.getCurrentState()
+ instanceof IkeSessionStateMachine.ChildProcedureOngoing);
+ }
+
@Test
public void testCreateIkeLocalIkeAuthDigitalSignature() throws Exception {
// Quit and restart IKE Session with Digital Signature Auth params