diff options
author | android-build-team Robot <android-build-team-robot@google.com> | 2019-11-11 21:24:43 +0000 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2019-11-11 21:24:43 +0000 |
commit | be2e569365fb597b26939bb475e88d99b3da2d63 (patch) | |
tree | b39c3e794945072d38b97c963c5a6f10753514e1 /tests/iketests/src/java/com/android/ike/ikev2/IkeSessionStateMachineTest.java | |
parent | 78052775925ce7e49f6013e2fbea4130779f13cf (diff) | |
parent | eb4c77d7228f956f928c7d3500a220339ee78388 (diff) | |
download | ike-android10-mainline-networking-release.tar.gz |
Snap for 6001391 from eb4c77d7228f956f928c7d3500a220339ee78388 to qt-aml-networking-releaseandroid-mainline-10.0.0_r6android10-mainline-networking-release
Change-Id: Ifede049eeae909912e9792f87a89bf4ede7e34d9
Diffstat (limited to 'tests/iketests/src/java/com/android/ike/ikev2/IkeSessionStateMachineTest.java')
-rw-r--r-- | tests/iketests/src/java/com/android/ike/ikev2/IkeSessionStateMachineTest.java | 4025 |
1 files changed, 0 insertions, 4025 deletions
diff --git a/tests/iketests/src/java/com/android/ike/ikev2/IkeSessionStateMachineTest.java b/tests/iketests/src/java/com/android/ike/ikev2/IkeSessionStateMachineTest.java deleted file mode 100644 index 819c3280..00000000 --- a/tests/iketests/src/java/com/android/ike/ikev2/IkeSessionStateMachineTest.java +++ /dev/null @@ -1,4025 +0,0 @@ -/* - * Copyright (C) 2019 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.android.ike.ikev2; - -import static com.android.ike.ikev2.IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE; -import static com.android.ike.ikev2.IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET; -import static com.android.ike.ikev2.IkeSessionStateMachine.IKE_EXCHANGE_SUBTYPE_DELETE_CHILD; -import static com.android.ike.ikev2.IkeSessionStateMachine.IKE_EXCHANGE_SUBTYPE_REKEY_CHILD; -import static com.android.ike.ikev2.IkeSessionStateMachine.RETRY_INTERVAL_MS; -import static com.android.ike.ikev2.IkeSessionStateMachine.SA_SOFT_LIFETIME_MS; -import static com.android.ike.ikev2.IkeSessionStateMachine.TEMP_FAILURE_RETRY_TIMEOUT_MS; -import static com.android.ike.ikev2.exceptions.IkeProtocolException.ERROR_TYPE_CHILD_SA_NOT_FOUND; -import static com.android.ike.ikev2.exceptions.IkeProtocolException.ERROR_TYPE_INVALID_SYNTAX; -import static com.android.ike.ikev2.exceptions.IkeProtocolException.ERROR_TYPE_NO_ADDITIONAL_SAS; -import static com.android.ike.ikev2.exceptions.IkeProtocolException.ERROR_TYPE_NO_PROPOSAL_CHOSEN; -import static com.android.ike.ikev2.exceptions.IkeProtocolException.ERROR_TYPE_TEMPORARY_FAILURE; -import static com.android.ike.ikev2.exceptions.IkeProtocolException.ERROR_TYPE_UNSUPPORTED_CRITICAL_PAYLOAD; -import static com.android.ike.ikev2.message.IkeHeader.EXCHANGE_TYPE_CREATE_CHILD_SA; -import static com.android.ike.ikev2.message.IkeHeader.EXCHANGE_TYPE_INFORMATIONAL; -import static com.android.ike.ikev2.message.IkeNotifyPayload.NOTIFY_TYPE_IKEV2_FRAGMENTATION_SUPPORTED; -import static com.android.ike.ikev2.message.IkeNotifyPayload.NOTIFY_TYPE_NAT_DETECTION_DESTINATION_IP; -import static com.android.ike.ikev2.message.IkeNotifyPayload.NOTIFY_TYPE_NAT_DETECTION_SOURCE_IP; -import static com.android.ike.ikev2.message.IkePayload.PAYLOAD_TYPE_AUTH; -import static com.android.ike.ikev2.message.IkePayload.PAYLOAD_TYPE_NOTIFY; -import static com.android.ike.ikev2.message.IkePayload.PAYLOAD_TYPE_SA; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyBoolean; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.anyObject; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.argThat; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.content.Context; -import android.net.IpSecManager; -import android.net.IpSecManager.UdpEncapsulationSocket; -import android.os.test.TestLooper; -import android.telephony.TelephonyManager; - -import com.android.ike.TestUtils; -import com.android.ike.eap.EapAuthenticator; -import com.android.ike.eap.EapSessionConfig; -import com.android.ike.eap.IEapCallback; -import com.android.ike.ikev2.ChildSessionStateMachine.IChildSessionSmCallback; -import com.android.ike.ikev2.ChildSessionStateMachineFactory.ChildSessionFactoryHelper; -import com.android.ike.ikev2.ChildSessionStateMachineFactory.IChildSessionFactoryHelper; -import com.android.ike.ikev2.IkeLocalRequestScheduler.ChildLocalRequest; -import com.android.ike.ikev2.IkeLocalRequestScheduler.LocalRequest; -import com.android.ike.ikev2.IkeSessionStateMachine.IkeSecurityParameterIndex; -import com.android.ike.ikev2.IkeSessionStateMachine.ReceivedIkePacket; -import com.android.ike.ikev2.SaRecord.ISaRecordHelper; -import com.android.ike.ikev2.SaRecord.IkeSaRecord; -import com.android.ike.ikev2.SaRecord.IkeSaRecordConfig; -import com.android.ike.ikev2.SaRecord.SaRecordHelper; -import com.android.ike.ikev2.crypto.IkeCipher; -import com.android.ike.ikev2.crypto.IkeMacIntegrity; -import com.android.ike.ikev2.crypto.IkeMacPrf; -import com.android.ike.ikev2.exceptions.AuthenticationFailedException; -import com.android.ike.ikev2.exceptions.IkeException; -import com.android.ike.ikev2.exceptions.IkeInternalException; -import com.android.ike.ikev2.exceptions.IkeProtocolException; -import com.android.ike.ikev2.exceptions.InvalidSyntaxException; -import com.android.ike.ikev2.exceptions.NoValidProposalChosenException; -import com.android.ike.ikev2.exceptions.UnsupportedCriticalPayloadException; -import com.android.ike.ikev2.message.IkeAuthDigitalSignPayload; -import com.android.ike.ikev2.message.IkeAuthPayload; -import com.android.ike.ikev2.message.IkeAuthPskPayload; -import com.android.ike.ikev2.message.IkeCertX509CertPayload; -import com.android.ike.ikev2.message.IkeDeletePayload; -import com.android.ike.ikev2.message.IkeEapPayload; -import com.android.ike.ikev2.message.IkeHeader; -import com.android.ike.ikev2.message.IkeIdPayload; -import com.android.ike.ikev2.message.IkeInformationalPayload; -import com.android.ike.ikev2.message.IkeKePayload; -import com.android.ike.ikev2.message.IkeMessage; -import com.android.ike.ikev2.message.IkeMessage.DecodeResult; -import com.android.ike.ikev2.message.IkeMessage.DecodeResultOk; -import com.android.ike.ikev2.message.IkeMessage.DecodeResultPartial; -import com.android.ike.ikev2.message.IkeMessage.DecodeResultProtectedError; -import com.android.ike.ikev2.message.IkeMessage.DecodeResultUnprotectedError; -import com.android.ike.ikev2.message.IkeMessage.IIkeMessageHelper; -import com.android.ike.ikev2.message.IkeMessage.IkeMessageHelper; -import com.android.ike.ikev2.message.IkeNoncePayload; -import com.android.ike.ikev2.message.IkeNotifyPayload; -import com.android.ike.ikev2.message.IkePayload; -import com.android.ike.ikev2.message.IkeSaPayload; -import com.android.ike.ikev2.message.IkeSaPayload.DhGroupTransform; -import com.android.ike.ikev2.message.IkeSaPayload.EncryptionTransform; -import com.android.ike.ikev2.message.IkeSaPayload.IntegrityTransform; -import com.android.ike.ikev2.message.IkeSaPayload.PrfTransform; -import com.android.ike.ikev2.message.IkeSkfPayload; -import com.android.ike.ikev2.message.IkeTestUtils; -import com.android.ike.ikev2.message.IkeTsPayload; -import com.android.ike.ikev2.testutils.CertUtils; -import com.android.ike.ikev2.testutils.MockIpSecTestUtils; -import com.android.ike.ikev2.utils.Retransmitter; -import com.android.ike.ikev2.utils.Retransmitter.IBackoffTimeoutCalculator; -import com.android.ike.utils.Log; -import com.android.internal.util.State; - -import libcore.net.InetAddressUtils; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.invocation.InvocationOnMock; - -import java.io.IOException; -import java.net.Inet4Address; -import java.security.GeneralSecurityException; -import java.security.cert.X509Certificate; -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; -import java.util.concurrent.Executor; - -public final class IkeSessionStateMachineTest { - private static final String TAG = "IkeSessionStateMachineTest"; - - private static final Inet4Address LOCAL_ADDRESS = - (Inet4Address) (InetAddressUtils.parseNumericAddress("192.0.2.200")); - private static final Inet4Address REMOTE_ADDRESS = - (Inet4Address) (InetAddressUtils.parseNumericAddress("127.0.0.1")); - - private static final String IKE_INIT_RESP_HEX_STRING = - "5f54bf6d8b48e6e1909232b3d1edcb5c21202220000000000000014c220000300000" - + "002c010100040300000c0100000c800e008003000008030000020300000802000002" - + "00000008040000022800008800020000fe014fefed55a4229928bfa3dad1ea6ffaca" - + "abfb5f5bdd71790e99a192530e3f849d3a3d96dc6e0a7a10ff6f72a6162103ac573c" - + "acd41d08b7a034cad8f5eab09c14ced5a9e4af5692dff028f21c1119dd75226b6af6" - + "b2f009245369c9892cc5742e5c94a254ebff052470771fb2cb4f29a35d8953e18a1a" - + "6c6fbc56acc188a5290000249756112ca539f5c25abacc7ee92b73091942a9c06950" - + "f98848f1af1694c4ddff2900001c00004004c53f054b976a25d75fde72dbf1c7b6c8" - + "c9aa9ca12900001c00004005b16d79b21c1bc89ca7350f42de805be0227e2ed62b00" - + "00080000401400000014882fe56d6fd20dbc2251613b2ebe5beb"; - private static final String IKE_SA_PAYLOAD_HEX_STRING = - "220000300000002c010100040300000c0100000c800e00800300000803000002030" - + "00008020000020000000804000002"; - private static final String IKE_REKEY_SA_PAYLOAD_HEX_STRING = - "22000038000000340101080400000000000000FF0300000c0100000c800e0080030" - + "000080300000203000008020000020000000804000002"; - private static final String IKE_REKEY_UNACCEPTABLE_SA_PAYLOAD_HEX_STRING = - "22000038000000340101080400000000000000FF0300000c0100000c800e0080030" - + "00008030000020300000802000002000000080400000e"; - private static final int IKE_REKEY_SA_INITIATOR_SPI = 0xff; - private static final String KE_PAYLOAD_HEX_STRING = - "2800008800020000b4a2faf4bb54878ae21d638512ece55d9236fc50" - + "46ab6cef82220f421f3ce6361faf36564ecb6d28798a94aa" - + "d7b2b4b603ddeaaa5630adb9ece8ac37534036040610ebdd" - + "92f46bef84f0be7db860351843858f8acf87056e272377f7" - + "0c9f2d81e29c7b0ce4f291a3a72476bb0b278fd4b7b0a4c2" - + "6bbeb08214c7071376079587"; - private static final String NONCE_INIT_PAYLOAD_HEX_STRING = - "29000024c39b7f368f4681b89fa9b7be6465abd7c5f68b6ed5d3b4c72cb4240eb5c46412"; - private static final String NONCE_RESP_PAYLOAD_HEX_STRING = - "290000249756112ca539f5c25abacc7ee92b73091942a9c06950f98848f1af1694c4ddff"; - private static final String NONCE_INIT_HEX_STRING = - "c39b7f368f4681b89fa9b7be6465abd7c5f68b6ed5d3b4c72cb4240eb5c46412"; - private static final String NONCE_RESP_HEX_STRING = - "9756112ca539f5c25abacc7ee92b73091942a9c06950f98848f1af1694c4ddff"; - private static final String NAT_DETECTION_SOURCE_PAYLOAD_HEX_STRING = - "2900001c00004004e54f73b7d83f6beb881eab2051d8663f421d10b0"; - private static final String NAT_DETECTION_DESTINATION_PAYLOAD_HEX_STRING = - "2b00001c00004005d915368ca036004cb578ae3e3fb268509aeab190"; - private static final String FRAGMENTATION_SUPPORTED_PAYLOAD_HEX_STRING = "290000080000402e"; - private static final String DELETE_IKE_PAYLOAD_HEX_STRING = "0000000801000000"; - private static final String NOTIFY_REKEY_IKE_PAYLOAD_HEX_STRING = "2100000800004009"; - private static final String ID_PAYLOAD_INITIATOR_HEX_STRING = - "290000180200000031313233343536373839414243444546"; - private static final String ID_PAYLOAD_RESPONDER_HEX_STRING = "2700000c010000007f000001"; - private static final String PSK_AUTH_RESP_PAYLOAD_HEX_STRING = - "2100001c0200000058f36412e9b7b38df817a9f7779b7a008dacdd25"; - private static final String GENERIC_DIGITAL_SIGN_AUTH_RESP_HEX_STRING = - "300000580e0000000f300d06092a864886f70d01010b05006f76af4150d653c5d413" - + "6b9f69d905849bf075c563e6d14ccda42361ec3e7d12c72e2dece5711ea1d952f7b8e" - + "12c5d982aa4efdaeac36a02b222aa96242cc424"; - private static final String CHILD_SA_PAYLOAD_HEX_STRING = - "2c00002c0000002801030403cae7019f0300000c0100000c800e008003000008030" - + "000020000000805000000"; - private static final String TS_INIT_PAYLOAD_HEX_STRING = - "2d00001801000000070000100000ffff00000000ffffffff"; - private static final String TS_RESP_PAYLOAD_HEX_STRING = - "2900001801000000070000100000ffff000000000fffffff"; - - private static final String PSK_HEX_STRING = "6A756E69706572313233"; - - private static final String PRF_KEY_INIT_HEX_STRING = - "094787780EE466E2CB049FA327B43908BC57E485"; - private static final String PRF_KEY_RESP_HEX_STRING = - "A30E6B08BE56C0E6BFF4744143C75219299E1BEB"; - - private static final byte[] EAP_DUMMY_MSG = "EAP Message".getBytes(); - - private static final int KEY_LEN_IKE_INTE = 20; - private static final int KEY_LEN_IKE_ENCR = 16; - private static final int KEY_LEN_IKE_PRF = 20; - private static final int KEY_LEN_IKE_SKD = KEY_LEN_IKE_PRF; - - private static final int CHILD_SPI_LOCAL = 0x2ad4c0a2; - private static final int CHILD_SPI_REMOTE = 0xcae7019f; - - private static final int DUMMY_UDP_ENCAP_RESOURCE_ID = 0x3234; - private static final int UDP_ENCAP_PORT = 34567; - - private static final int EAP_SIM_SUB_ID = 1; - - private static final int PAYLOAD_TYPE_UNSUPPORTED = 127; - - private static final long RETRANSMIT_BACKOFF_TIMEOUT_MS = 5000L; - - private MockIpSecTestUtils mMockIpSecTestUtils; - private Context mContext; - private IpSecManager mIpSecManager; - private UdpEncapsulationSocket mUdpEncapSocket; - - private IkeSocket mSpyIkeSocket; - - private TestLooper mLooper; - private IkeSessionStateMachine mIkeSessionStateMachine; - - private byte[] mPsk; - - private ChildSessionOptions mChildSessionOptions; - - private Executor mSpyUserCbExecutor; - private IkeSessionCallback mMockIkeSessionCallback; - private ChildSessionCallback mMockChildSessionCallback; - - private EncryptionTransform mIkeEncryptionTransform; - private IntegrityTransform mIkeIntegrityTransform; - private PrfTransform mIkePrfTransform; - private DhGroupTransform mIkeDhGroupTransform; - - private IIkeMessageHelper mMockIkeMessageHelper; - private ISaRecordHelper mMockSaRecordHelper; - private IBackoffTimeoutCalculator mMockBackoffTimeoutCalculator; - - private ChildSessionStateMachine mMockChildSessionStateMachine; - private IChildSessionFactoryHelper mMockChildSessionFactoryHelper; - private IChildSessionSmCallback mDummyChildSmCallback; - - private IkeSaRecord mSpyCurrentIkeSaRecord; - private IkeSaRecord mSpyLocalInitIkeSaRecord; - private IkeSaRecord mSpyRemoteInitIkeSaRecord; - - private Log mSpyIkeLog; - - private int mExpectedCurrentSaLocalReqMsgId; - private int mExpectedCurrentSaRemoteReqMsgId; - - private EapSessionConfig mEapSessionConfig; - private IkeEapAuthenticatorFactory mMockEapAuthenticatorFactory; - private EapAuthenticator mMockEapAuthenticator; - - private X509Certificate mRootCertificate; - private X509Certificate mServerEndCertificate; - - private ArgumentCaptor<IkeMessage> mIkeMessageCaptor = - ArgumentCaptor.forClass(IkeMessage.class); - private ArgumentCaptor<IkeSaRecordConfig> mIkeSaRecordConfigCaptor = - ArgumentCaptor.forClass(IkeSaRecordConfig.class); - private ArgumentCaptor<IChildSessionSmCallback> mChildSessionSmCbCaptor = - ArgumentCaptor.forClass(IChildSessionSmCallback.class); - private ArgumentCaptor<List<IkePayload>> mPayloadListCaptor = - ArgumentCaptor.forClass(List.class); - - private ReceivedIkePacket makeDummyReceivedIkeInitRespPacket( - long initiatorSpi, - long responderSpi, - @IkeHeader.ExchangeType int eType, - boolean isResp, - boolean fromIkeInit, - List<Integer> payloadTypeList, - List<String> payloadHexStringList) - throws Exception { - - List<IkePayload> payloadList = - hexStrListToIkePayloadList(payloadTypeList, payloadHexStringList, isResp); - // Build a remotely generated NAT_DETECTION_SOURCE_IP payload to mock a remote node's - // network that is not behind NAT. - IkePayload sourceNatPayload = - new IkeNotifyPayload( - NOTIFY_TYPE_NAT_DETECTION_SOURCE_IP, - IkeNotifyPayload.generateNatDetectionData( - initiatorSpi, - responderSpi, - REMOTE_ADDRESS, - IkeSocket.IKE_SERVER_PORT)); - payloadList.add(sourceNatPayload); - return makeDummyUnencryptedReceivedIkePacket( - initiatorSpi, responderSpi, eType, isResp, fromIkeInit, payloadList); - } - - private ReceivedIkePacket makeDummyUnencryptedReceivedIkePacket( - long initiatorSpi, - long responderSpi, - @IkeHeader.ExchangeType int eType, - boolean isResp, - boolean fromIkeInit, - List<IkePayload> payloadList) - throws Exception { - IkeMessage dummyIkeMessage = - makeDummyIkeMessageForTest( - initiatorSpi, - responderSpi, - eType, - isResp, - fromIkeInit, - 0, - false /*isEncrypted*/, - payloadList); - - byte[] dummyIkePacketBytes = new byte[0]; - when(mMockIkeMessageHelper.decode(0, dummyIkeMessage.ikeHeader, dummyIkePacketBytes)) - .thenReturn(new DecodeResultOk(dummyIkeMessage, dummyIkePacketBytes)); - - return new ReceivedIkePacket(dummyIkeMessage.ikeHeader, dummyIkePacketBytes); - } - - private ReceivedIkePacket makeDummyEncryptedReceivedIkePacket( - IkeSaRecord ikeSaRecord, - @IkeHeader.ExchangeType int eType, - boolean isResp, - List<Integer> payloadTypeList, - List<String> payloadHexStringList) - throws Exception { - List<IkePayload> payloadList = - hexStrListToIkePayloadList(payloadTypeList, payloadHexStringList, isResp); - return makeDummyEncryptedReceivedIkePacketWithPayloadList( - ikeSaRecord, eType, isResp, payloadList); - } - - private ReceivedIkePacket makeDummyEncryptedReceivedIkePacketWithPayloadList( - IkeSaRecord ikeSaRecord, - @IkeHeader.ExchangeType int eType, - boolean isResp, - List<IkePayload> payloadList) - throws Exception { - return makeDummyEncryptedReceivedIkePacketWithPayloadList( - ikeSaRecord, - eType, - isResp, - isResp - ? ikeSaRecord.getLocalRequestMessageId() - : ikeSaRecord.getRemoteRequestMessageId(), - payloadList, - new byte[0] /*dummyIkePacketBytes*/); - } - - private ReceivedIkePacket makeDummyEncryptedReceivedIkePacketWithPayloadList( - IkeSaRecord ikeSaRecord, - @IkeHeader.ExchangeType int eType, - boolean isResp, - int msgId, - List<IkePayload> payloadList, - byte[] dummyIkePacketBytes) - throws Exception { - boolean fromIkeInit = !ikeSaRecord.isLocalInit; - IkeMessage dummyIkeMessage = - makeDummyIkeMessageForTest( - ikeSaRecord.getInitiatorSpi(), - ikeSaRecord.getResponderSpi(), - eType, - isResp, - fromIkeInit, - msgId, - true /*isEncyprted*/, - payloadList); - - setDecodeEncryptedPacketResult( - ikeSaRecord, - dummyIkeMessage.ikeHeader, - null /*collectedFrags*/, - new DecodeResultOk(dummyIkeMessage, dummyIkePacketBytes)); - - return new ReceivedIkePacket(dummyIkeMessage.ikeHeader, dummyIkePacketBytes); - } - - private ReceivedIkePacket makeDummyReceivedIkePacketWithInvalidSyntax( - IkeSaRecord ikeSaRecord, boolean isResp, int eType) { - return makeDummyReceivedIkePacketWithDecodingError( - ikeSaRecord, isResp, eType, new InvalidSyntaxException("IkeStateMachineTest")); - } - - private ReceivedIkePacket makeDummyReceivedIkePacketWithDecodingError( - IkeSaRecord ikeSaRecord, boolean isResp, int eType, IkeProtocolException exception) { - IkeHeader header = - makeDummyIkeHeader(ikeSaRecord, isResp, eType, IkePayload.PAYLOAD_TYPE_SK); - byte[] dummyPacket = new byte[0]; - when(mMockIkeMessageHelper.decode( - anyInt(), any(), any(), eq(ikeSaRecord), eq(header), any(), any())) - .thenReturn(new DecodeResultProtectedError(exception, dummyPacket)); - - return new ReceivedIkePacket(header, dummyPacket); - } - - private ReceivedIkePacket makeDummyReceivedIkePacketWithUnprotectedError( - IkeSaRecord ikeSaRecord, boolean isResp, int eType, IkeException exception) { - IkeHeader header = - makeDummyIkeHeader(ikeSaRecord, isResp, eType, IkePayload.PAYLOAD_TYPE_SK); - byte[] dummyPacket = new byte[0]; - when(mMockIkeMessageHelper.decode( - anyInt(), any(), any(), eq(ikeSaRecord), eq(header), any(), any())) - .thenReturn(new DecodeResultUnprotectedError(exception)); - - return new ReceivedIkePacket(header, dummyPacket); - } - - private ReceivedIkePacket makeDummyReceivedIkeFragmentPacket( - IkeSaRecord ikeSaRecord, - boolean isResp, - int eType, - IkeSkfPayload skfPayload, - int nextPayloadType, - DecodeResultPartial collectedFrags) { - IkeHeader header = - makeDummyIkeHeader(ikeSaRecord, isResp, eType, IkePayload.PAYLOAD_TYPE_SKF); - - byte[] dummyPacket = new byte[0]; - DecodeResultPartial resultFrags = - new DecodeResultPartial( - header, dummyPacket, skfPayload, nextPayloadType, collectedFrags); - setDecodeEncryptedPacketResult(ikeSaRecord, header, collectedFrags, resultFrags); - - return new ReceivedIkePacket(header, dummyPacket); - } - - private ReceivedIkePacket makeDummyReceivedLastIkeFragmentPacketOk( - IkeSaRecord ikeSaRecord, - boolean isResp, - int eType, - DecodeResultPartial collectedFrags, - List<IkePayload> payloadList, - byte[] firstFragBytes) { - IkeHeader header = - makeDummyIkeHeader(ikeSaRecord, isResp, eType, IkePayload.PAYLOAD_TYPE_SKF); - - IkeMessage completeMessage = new IkeMessage(header, payloadList); - - setDecodeEncryptedPacketResult( - ikeSaRecord, - header, - collectedFrags, - new DecodeResultOk(completeMessage, firstFragBytes)); - - return new ReceivedIkePacket(header, new byte[0] /*dummyIkePacketBytes*/); - } - - private ReceivedIkePacket makeDummyReceivedLastIkeFragmentPacketError( - IkeSaRecord ikeSaRecord, - boolean isResp, - int eType, - DecodeResultPartial collectedFrags, - IkeException exception) { - IkeHeader header = - makeDummyIkeHeader(ikeSaRecord, isResp, eType, IkePayload.PAYLOAD_TYPE_SKF); - - byte[] dummyIkePacketBytes = new byte[0]; - setDecodeEncryptedPacketResult( - ikeSaRecord, - header, - collectedFrags, - new DecodeResultProtectedError(exception, dummyIkePacketBytes)); - - return new ReceivedIkePacket(header, dummyIkePacketBytes); - } - - private IkeHeader makeDummyIkeHeader( - IkeSaRecord ikeSaRecord, boolean isResp, int eType, int firstPayloadType) { - return new IkeHeader( - ikeSaRecord.getInitiatorSpi(), - ikeSaRecord.getResponderSpi(), - firstPayloadType, - eType, - isResp, - !ikeSaRecord.isLocalInit, - isResp - ? ikeSaRecord.getLocalRequestMessageId() - : ikeSaRecord.getRemoteRequestMessageId()); - } - - private void setDecodeEncryptedPacketResult( - IkeSaRecord ikeSaRecord, - IkeHeader header, - DecodeResultPartial collectedFrags, - DecodeResult result) { - when(mMockIkeMessageHelper.decode( - anyInt(), - any(), - any(), - eq(ikeSaRecord), - eq(header), - any(), - eq(collectedFrags))) - .thenReturn(result); - } - - private IkeMessage makeDummyIkeMessageForTest( - long initSpi, - long respSpi, - @IkeHeader.ExchangeType int eType, - boolean isResp, - boolean fromikeInit, - int messageId, - boolean isEncrypted, - List<IkePayload> payloadList) - throws Exception { - int firstPayloadType = - isEncrypted ? IkePayload.PAYLOAD_TYPE_SK : IkePayload.PAYLOAD_TYPE_NO_NEXT; - - IkeHeader header = - new IkeHeader( - initSpi, respSpi, firstPayloadType, eType, isResp, fromikeInit, messageId); - - return new IkeMessage(header, payloadList); - } - - private static List<IkePayload> hexStrListToIkePayloadList( - List<Integer> payloadTypeList, List<String> payloadHexStringList, boolean isResp) - throws Exception { - List<IkePayload> payloadList = new LinkedList<>(); - for (int i = 0; i < payloadTypeList.size(); i++) { - payloadList.add( - IkeTestUtils.hexStringToIkePayload( - payloadTypeList.get(i), isResp, payloadHexStringList.get(i))); - } - return payloadList; - } - - private void verifyDecodeEncryptedMessage(IkeSaRecord record, ReceivedIkePacket rcvPacket) - throws Exception { - verify(mMockIkeMessageHelper) - .decode( - anyInt(), - any(), - any(), - eq(record), - eq(rcvPacket.ikeHeader), - eq(rcvPacket.ikePacketBytes), - eq(null)); - } - - private static IkeSaRecord makeDummyIkeSaRecord(long initSpi, long respSpi, boolean isLocalInit) - throws IOException { - Inet4Address initAddress = isLocalInit ? LOCAL_ADDRESS : REMOTE_ADDRESS; - Inet4Address respAddress = isLocalInit ? REMOTE_ADDRESS : LOCAL_ADDRESS; - - return new IkeSaRecord( - IkeSecurityParameterIndex.allocateSecurityParameterIndex(initAddress, initSpi), - IkeSecurityParameterIndex.allocateSecurityParameterIndex(respAddress, respSpi), - isLocalInit, - TestUtils.hexStringToByteArray(NONCE_INIT_HEX_STRING), - TestUtils.hexStringToByteArray(NONCE_RESP_HEX_STRING), - new byte[KEY_LEN_IKE_SKD], - new byte[KEY_LEN_IKE_INTE], - new byte[KEY_LEN_IKE_INTE], - new byte[KEY_LEN_IKE_ENCR], - new byte[KEY_LEN_IKE_ENCR], - TestUtils.hexStringToByteArray(PRF_KEY_INIT_HEX_STRING), - TestUtils.hexStringToByteArray(PRF_KEY_RESP_HEX_STRING), - new LocalRequest(CMD_LOCAL_REQUEST_REKEY_IKE)); - } - - @Before - public void setUp() throws Exception { - mSpyIkeLog = TestUtils.makeSpyLogThrowExceptionForWtf(TAG); - IkeManager.setIkeLog(mSpyIkeLog); - - mMockIpSecTestUtils = MockIpSecTestUtils.setUpMockIpSec(); - mIpSecManager = mMockIpSecTestUtils.getIpSecManager(); - mContext = mMockIpSecTestUtils.getContext(); - mUdpEncapSocket = mIpSecManager.openUdpEncapsulationSocket(); - mEapSessionConfig = - new EapSessionConfig.Builder() - .setEapSimConfig(EAP_SIM_SUB_ID, TelephonyManager.APPTYPE_USIM) - .build(); - - mMockEapAuthenticatorFactory = mock(IkeEapAuthenticatorFactory.class); - mMockEapAuthenticator = mock(EapAuthenticator.class); - when(mMockEapAuthenticatorFactory.newEapAuthenticator(any(), any(), any(), any())) - .thenReturn(mMockEapAuthenticator); - - mRootCertificate = CertUtils.createCertFromPemFile("self-signed-ca-a.pem"); - mServerEndCertificate = CertUtils.createCertFromPemFile("end-cert-a.pem"); - - mPsk = TestUtils.hexStringToByteArray(PSK_HEX_STRING); - - mChildSessionOptions = buildChildSessionOptions(); - - mIkeEncryptionTransform = - new EncryptionTransform( - SaProposal.ENCRYPTION_ALGORITHM_AES_CBC, SaProposal.KEY_LEN_AES_128); - mIkeIntegrityTransform = - new IntegrityTransform(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96); - mIkePrfTransform = new PrfTransform(SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1); - mIkeDhGroupTransform = new DhGroupTransform(SaProposal.DH_GROUP_1024_BIT_MODP); - - mSpyUserCbExecutor = - spy( - (command) -> { - command.run(); - }); - - mMockIkeSessionCallback = mock(IkeSessionCallback.class); - mMockChildSessionCallback = mock(ChildSessionCallback.class); - - mLooper = new TestLooper(); - - mMockChildSessionStateMachine = mock(ChildSessionStateMachine.class); - mMockChildSessionFactoryHelper = mock(IChildSessionFactoryHelper.class); - ChildSessionStateMachineFactory.setChildSessionFactoryHelper( - mMockChildSessionFactoryHelper); - setupChildStateMachineFactory(mMockChildSessionStateMachine); - - // Inject longer retransmission timeout - mMockBackoffTimeoutCalculator = mock(IBackoffTimeoutCalculator.class); - when(mMockBackoffTimeoutCalculator.getExponentialBackoffTimeout(anyInt())) - .thenReturn(RETRANSMIT_BACKOFF_TIMEOUT_MS); - Retransmitter.setBackoffTimeoutCalculator(mMockBackoffTimeoutCalculator); - - // Setup state machine - mIkeSessionStateMachine = makeAndStartIkeSession(buildIkeSessionOptionsPsk(mPsk)); - - mMockIkeMessageHelper = mock(IkeMessage.IIkeMessageHelper.class); - IkeMessage.setIkeMessageHelper(mMockIkeMessageHelper); - resetMockIkeMessageHelper(); - - mMockSaRecordHelper = mock(SaRecord.ISaRecordHelper.class); - SaRecord.setSaRecordHelper(mMockSaRecordHelper); - - mSpyCurrentIkeSaRecord = spy(makeDummyIkeSaRecord(11, 12, true)); - mSpyLocalInitIkeSaRecord = spy(makeDummyIkeSaRecord(21, 22, true)); - mSpyRemoteInitIkeSaRecord = spy(makeDummyIkeSaRecord(31, 32, false)); - - mExpectedCurrentSaLocalReqMsgId = 0; - mExpectedCurrentSaRemoteReqMsgId = 0; - } - - @After - public void tearDown() throws Exception { - mIkeSessionStateMachine.quit(); - mIkeSessionStateMachine.setDbg(false); - mUdpEncapSocket.close(); - - mSpyCurrentIkeSaRecord.close(); - mSpyLocalInitIkeSaRecord.close(); - mSpyRemoteInitIkeSaRecord.close(); - - IkeManager.resetIkeLog(); - Retransmitter.resetBackoffTimeoutCalculator(); - IkeMessage.setIkeMessageHelper(new IkeMessageHelper()); - SaRecord.setSaRecordHelper(new SaRecordHelper()); - ChildSessionStateMachineFactory.setChildSessionFactoryHelper( - new ChildSessionFactoryHelper()); - } - - private IkeSessionStateMachine makeAndStartIkeSession(IkeSessionOptions ikeOptions) - throws Exception { - IkeSessionStateMachine ikeSession = - new IkeSessionStateMachine( - mLooper.getLooper(), - mContext, - mIpSecManager, - ikeOptions, - mChildSessionOptions, - mSpyUserCbExecutor, - mMockIkeSessionCallback, - mMockChildSessionCallback, - mMockEapAuthenticatorFactory); - ikeSession.setDbg(true); - - mLooper.dispatchAll(); - ikeSession.mLocalAddress = LOCAL_ADDRESS; - - mSpyIkeSocket = spy(IkeSocket.getIkeSocket(mUdpEncapSocket, ikeSession)); - doNothing().when(mSpyIkeSocket).sendIkePacket(any(), any()); - ikeSession.mIkeSocket = mSpyIkeSocket; - - return ikeSession; - } - - static IkeSaProposal buildSaProposal() throws Exception { - return new IkeSaProposal.Builder() - .addEncryptionAlgorithm( - SaProposal.ENCRYPTION_ALGORITHM_AES_CBC, SaProposal.KEY_LEN_AES_128) - .addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96) - .addPseudorandomFunction(SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1) - .addDhGroup(SaProposal.DH_GROUP_1024_BIT_MODP) - .build(); - } - - private IkeSessionOptions.Builder buildIkeSessionOptionsCommon() throws Exception { - return new IkeSessionOptions.Builder() - .setServerAddress(REMOTE_ADDRESS) - .setUdpEncapsulationSocket(mUdpEncapSocket) - .addSaProposal(buildSaProposal()) - .setLocalIdentification(new IkeIpv4AddrIdentification((Inet4Address) LOCAL_ADDRESS)) - .setRemoteIdentification( - new IkeIpv4AddrIdentification((Inet4Address) REMOTE_ADDRESS)); - } - - private IkeSessionOptions buildIkeSessionOptionsPsk(byte[] psk) throws Exception { - return buildIkeSessionOptionsCommon().setAuthPsk(psk).build(); - } - - private IkeSessionOptions buildIkeSessionOptionsEap() throws Exception { - return buildIkeSessionOptionsCommon() - .setAuthEap(mRootCertificate, mEapSessionConfig) - .build(); - } - - private ChildSessionOptions buildChildSessionOptions() throws Exception { - ChildSaProposal saProposal = - new ChildSaProposal.Builder() - .addEncryptionAlgorithm( - SaProposal.ENCRYPTION_ALGORITHM_AES_CBC, SaProposal.KEY_LEN_AES_128) - .addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96) - .build(); - - return new TransportModeChildSessionOptions.Builder().addSaProposal(saProposal).build(); - } - - private ReceivedIkePacket makeIkeInitResponse() throws Exception { - // TODO: Build real IKE INIT response when IKE INIT response validation is implemented. - List<Integer> payloadTypeList = new LinkedList<>(); - List<String> payloadHexStringList = new LinkedList<>(); - - payloadTypeList.add(IkePayload.PAYLOAD_TYPE_SA); - payloadTypeList.add(IkePayload.PAYLOAD_TYPE_KE); - payloadTypeList.add(IkePayload.PAYLOAD_TYPE_NONCE); - payloadTypeList.add(IkePayload.PAYLOAD_TYPE_NOTIFY); - payloadTypeList.add(IkePayload.PAYLOAD_TYPE_NOTIFY); - payloadTypeList.add(IkePayload.PAYLOAD_TYPE_NOTIFY); - - payloadHexStringList.add(IKE_SA_PAYLOAD_HEX_STRING); - payloadHexStringList.add(KE_PAYLOAD_HEX_STRING); - payloadHexStringList.add(NONCE_RESP_PAYLOAD_HEX_STRING); - payloadHexStringList.add(NAT_DETECTION_SOURCE_PAYLOAD_HEX_STRING); - payloadHexStringList.add(NAT_DETECTION_DESTINATION_PAYLOAD_HEX_STRING); - payloadHexStringList.add(FRAGMENTATION_SUPPORTED_PAYLOAD_HEX_STRING); - - // In each test assign different IKE responder SPI in IKE INIT response to avoid remote SPI - // collision during response validation. - // STOPSHIP: b/131617794 allow #mockIkeSetup to be independent in each test after we can - // support IkeSession cleanup. - return makeDummyReceivedIkeInitRespPacket( - 1L /*initiator SPI*/, - 2L /*responder SPI*/, - IkeHeader.EXCHANGE_TYPE_IKE_SA_INIT, - true /*isResp*/, - false /*fromIkeInit*/, - payloadTypeList, - payloadHexStringList); - } - - private List<IkePayload> getIkeAuthPayloadListWithChildPayloads( - List<IkePayload> authRelatedPayloads) throws Exception { - List<Integer> payloadTypeList = new LinkedList<>(); - List<String> payloadHexStringList = new LinkedList<>(); - - payloadTypeList.add(IkePayload.PAYLOAD_TYPE_SA); - payloadTypeList.add(IkePayload.PAYLOAD_TYPE_TS_INITIATOR); - payloadTypeList.add(IkePayload.PAYLOAD_TYPE_TS_RESPONDER); - - payloadHexStringList.add(CHILD_SA_PAYLOAD_HEX_STRING); - payloadHexStringList.add(TS_INIT_PAYLOAD_HEX_STRING); - payloadHexStringList.add(TS_RESP_PAYLOAD_HEX_STRING); - - List<IkePayload> payloadList = - hexStrListToIkePayloadList(payloadTypeList, payloadHexStringList, true /*isResp*/); - payloadList.addAll(authRelatedPayloads); - - return payloadList; - } - - private ReceivedIkePacket makeIkeAuthRespWithChildPayloads(List<IkePayload> authRelatedPayloads) - throws Exception { - List<IkePayload> payloadList = getIkeAuthPayloadListWithChildPayloads(authRelatedPayloads); - - return makeDummyEncryptedReceivedIkePacketWithPayloadList( - mSpyCurrentIkeSaRecord, - IkeHeader.EXCHANGE_TYPE_IKE_AUTH, - true /*isResp*/, - payloadList); - } - - private ReceivedIkePacket makeIkeAuthRespWithoutChildPayloads( - List<IkePayload> authRelatedPayloads) throws Exception { - return makeDummyEncryptedReceivedIkePacketWithPayloadList( - mSpyCurrentIkeSaRecord, - IkeHeader.EXCHANGE_TYPE_IKE_AUTH, - true /*isResp*/, - authRelatedPayloads); - } - - private ReceivedIkePacket makeCreateChildCreateMessage(boolean isResp) throws Exception { - return makeDummyEncryptedReceivedIkePacketWithPayloadList( - mSpyCurrentIkeSaRecord, - IkeHeader.EXCHANGE_TYPE_CREATE_CHILD_SA, - isResp, - makeCreateChildPayloadList(isResp)); - } - - private ReceivedIkePacket makeRekeyChildCreateMessage(boolean isResp, int spi) - throws Exception { - IkeNotifyPayload rekeyPayload = - new IkeNotifyPayload( - IkePayload.PROTOCOL_ID_ESP, - spi, - IkeNotifyPayload.NOTIFY_TYPE_REKEY_SA, - new byte[0]); - - List<IkePayload> payloadList = makeCreateChildPayloadList(isResp); - payloadList.add(rekeyPayload); - - return makeDummyEncryptedReceivedIkePacketWithPayloadList( - mSpyCurrentIkeSaRecord, - IkeHeader.EXCHANGE_TYPE_CREATE_CHILD_SA, - isResp, - payloadList); - } - - private List<IkePayload> makeCreateChildPayloadList(boolean isResp) throws Exception { - List<Integer> payloadTypeList = new LinkedList<>(); - List<String> payloadHexStringList = new LinkedList<>(); - - payloadTypeList.add(IkePayload.PAYLOAD_TYPE_SA); - payloadTypeList.add(IkePayload.PAYLOAD_TYPE_NONCE); - payloadTypeList.add(IkePayload.PAYLOAD_TYPE_TS_INITIATOR); - payloadTypeList.add(IkePayload.PAYLOAD_TYPE_TS_RESPONDER); - - payloadHexStringList.add(CHILD_SA_PAYLOAD_HEX_STRING); - payloadHexStringList.add(NONCE_RESP_PAYLOAD_HEX_STRING); - payloadHexStringList.add(TS_INIT_PAYLOAD_HEX_STRING); - payloadHexStringList.add(TS_RESP_PAYLOAD_HEX_STRING); - - return hexStrListToIkePayloadList(payloadTypeList, payloadHexStringList, isResp); - } - - private ReceivedIkePacket makeDeleteChildPacket(IkeDeletePayload[] payloads, boolean isResp) - throws Exception { - return makeDummyEncryptedReceivedIkePacketWithPayloadList( - mSpyCurrentIkeSaRecord, - IkeHeader.EXCHANGE_TYPE_INFORMATIONAL, - isResp, - Arrays.asList(payloads)); - } - - private ReceivedIkePacket makeRekeyIkeResponse() throws Exception { - List<Integer> payloadTypeList = new LinkedList<>(); - List<String> payloadHexStringList = new LinkedList<>(); - - payloadTypeList.add(IkePayload.PAYLOAD_TYPE_SA); - payloadTypeList.add(IkePayload.PAYLOAD_TYPE_KE); - payloadTypeList.add(IkePayload.PAYLOAD_TYPE_NONCE); - - payloadHexStringList.add(IKE_REKEY_SA_PAYLOAD_HEX_STRING); - payloadHexStringList.add(KE_PAYLOAD_HEX_STRING); - payloadHexStringList.add(NONCE_RESP_PAYLOAD_HEX_STRING); - - return makeDummyEncryptedReceivedIkePacket( - mSpyCurrentIkeSaRecord, - IkeHeader.EXCHANGE_TYPE_CREATE_CHILD_SA, - true /*isResp*/, - payloadTypeList, - payloadHexStringList); - } - - private ReceivedIkePacket makeDeleteIkeResponse(IkeSaRecord ikeSaRecord) throws Exception { - return makeDummyEncryptedReceivedIkePacket( - ikeSaRecord, - IkeHeader.EXCHANGE_TYPE_INFORMATIONAL, - true /*isResp*/, - new LinkedList<>(), - new LinkedList<>()); - } - - private ReceivedIkePacket makeDpdIkeRequest(IkeSaRecord saRecord) throws Exception { - return makeDummyEncryptedReceivedIkePacket( - saRecord, - IkeHeader.EXCHANGE_TYPE_INFORMATIONAL, - false /*isResp*/, - new LinkedList<>(), - new LinkedList<>()); - } - - private ReceivedIkePacket makeDpdIkeRequest(int msgId, byte[] dummyIkePacketBytes) - throws Exception { - return makeDummyEncryptedReceivedIkePacketWithPayloadList( - mSpyCurrentIkeSaRecord, - EXCHANGE_TYPE_INFORMATIONAL, - false /*isResp*/, - msgId, - new LinkedList<>(), - dummyIkePacketBytes); - } - - private ReceivedIkePacket makeRekeyIkeRequest() throws Exception { - IkeSaPayload saPayload = - (IkeSaPayload) - IkeTestUtils.hexStringToIkePayload( - IkePayload.PAYLOAD_TYPE_SA, - false /*isResp*/, - IKE_REKEY_SA_PAYLOAD_HEX_STRING); - return makeRekeyIkeRequest(saPayload); - } - - private ReceivedIkePacket makeRekeyIkeRequestWithUnacceptableProposal() throws Exception { - IkeSaPayload saPayload = - (IkeSaPayload) - IkeTestUtils.hexStringToIkePayload( - IkePayload.PAYLOAD_TYPE_SA, - false /*isResp*/, - IKE_REKEY_UNACCEPTABLE_SA_PAYLOAD_HEX_STRING); - return makeRekeyIkeRequest(saPayload); - } - - private ReceivedIkePacket makeRekeyIkeRequest(IkeSaPayload saPayload) throws Exception { - List<Integer> payloadTypeList = new LinkedList<>(); - List<String> payloadHexStringList = new LinkedList<>(); - - payloadTypeList.add(IkePayload.PAYLOAD_TYPE_KE); - payloadTypeList.add(IkePayload.PAYLOAD_TYPE_NONCE); - - payloadHexStringList.add(KE_PAYLOAD_HEX_STRING); - payloadHexStringList.add(NONCE_INIT_PAYLOAD_HEX_STRING); - - List<IkePayload> payloadList = - hexStrListToIkePayloadList(payloadTypeList, payloadHexStringList, false /*isResp*/); - payloadList.add(saPayload); - - return makeDummyEncryptedReceivedIkePacketWithPayloadList( - mSpyCurrentIkeSaRecord, - IkeHeader.EXCHANGE_TYPE_CREATE_CHILD_SA, - false /*isResp*/, - payloadList); - } - - private ReceivedIkePacket makeDeleteIkeRequest(IkeSaRecord saRecord) throws Exception { - List<Integer> payloadTypeList = new LinkedList<>(); - List<String> payloadHexStringList = new LinkedList<>(); - - payloadTypeList.add(IkePayload.PAYLOAD_TYPE_DELETE); - - payloadHexStringList.add(DELETE_IKE_PAYLOAD_HEX_STRING); - - return makeDummyEncryptedReceivedIkePacket( - saRecord, - IkeHeader.EXCHANGE_TYPE_INFORMATIONAL, - false /*isResp*/, - payloadTypeList, - payloadHexStringList); - } - - private ReceivedIkePacket makeResponseWithErrorNotify(IkeNotifyPayload notify) - throws Exception { - List<IkePayload> payloads = new LinkedList<>(); - payloads.add(notify); - return makeDummyEncryptedReceivedIkePacketWithPayloadList( - mSpyCurrentIkeSaRecord, EXCHANGE_TYPE_INFORMATIONAL, true /*isResp*/, payloads); - } - - private static boolean isIkePayloadExist( - List<IkePayload> payloadList, @IkePayload.PayloadType int payloadType) { - for (IkePayload payload : payloadList) { - if (payload.payloadType == payloadType) return true; - } - return false; - } - - private static boolean isNotifyExist( - List<IkePayload> payloadList, @IkeNotifyPayload.NotifyType int notifyType) { - for (IkeNotifyPayload notify : - IkePayload.getPayloadListForTypeInProvidedList( - PAYLOAD_TYPE_NOTIFY, IkeNotifyPayload.class, payloadList)) { - if (notify.notifyType == notifyType) return true; - } - return false; - } - - private void verifyIncrementLocaReqMsgId() { - assertEquals( - ++mExpectedCurrentSaLocalReqMsgId, - mSpyCurrentIkeSaRecord.getLocalRequestMessageId()); - } - - private void verifyIncrementRemoteReqMsgId() { - assertEquals( - ++mExpectedCurrentSaRemoteReqMsgId, - mSpyCurrentIkeSaRecord.getRemoteRequestMessageId()); - } - - private void verifyRetransmissionStarted() { - assertTrue( - mIkeSessionStateMachine - .getHandler() - .hasMessages(IkeSessionStateMachine.CMD_RETRANSMIT)); - } - - private void verifyRetransmissionStopped() { - assertFalse( - mIkeSessionStateMachine - .getHandler() - .hasMessages(IkeSessionStateMachine.CMD_RETRANSMIT)); - } - - private IkeMessage verifyEncryptAndEncodeAndGetMessage(IkeSaRecord ikeSaRecord) { - verify(mMockIkeMessageHelper) - .encryptAndEncode( - anyObject(), - anyObject(), - eq(ikeSaRecord), - mIkeMessageCaptor.capture(), - anyBoolean(), - anyInt()); - return mIkeMessageCaptor.getValue(); - } - - private void verifyEncryptAndEncodeNeverCalled(IkeSaRecord ikeSaRecord) { - verify(mMockIkeMessageHelper, never()) - .encryptAndEncode( - anyObject(), - anyObject(), - eq(ikeSaRecord), - any(IkeMessage.class), - anyBoolean(), - anyInt()); - } - - private void verifyEncryptAndEncodeNeverCalled() { - verify(mMockIkeMessageHelper, never()) - .encryptAndEncode( - anyObject(), - anyObject(), - any(IkeSaRecord.class), - any(IkeMessage.class), - anyBoolean(), - anyInt()); - } - - private void resetMockIkeMessageHelper() { - reset(mMockIkeMessageHelper); - when(mMockIkeMessageHelper.encode(any())).thenReturn(new byte[0]); - when(mMockIkeMessageHelper.encryptAndEncode( - any(), any(), any(), any(), anyBoolean(), anyInt())) - .thenReturn(new byte[1][0]); - } - - @Test - public void testQuit() { - mIkeSessionStateMachine.quit(); - mLooper.dispatchAll(); - - verify(mSpyIkeSocket).releaseReference(eq(mIkeSessionStateMachine)); - verify(mSpyIkeSocket).close(); - } - - @Test - public void testAllocateIkeSpi() throws Exception { - // Test randomness. - IkeSecurityParameterIndex ikeSpiOne = - IkeSecurityParameterIndex.allocateSecurityParameterIndex(LOCAL_ADDRESS); - IkeSecurityParameterIndex ikeSpiTwo = - IkeSecurityParameterIndex.allocateSecurityParameterIndex(LOCAL_ADDRESS); - - assertNotEquals(ikeSpiOne.getSpi(), ikeSpiTwo.getSpi()); - ikeSpiTwo.close(); - - // Test duplicate SPIs. - long spiValue = ikeSpiOne.getSpi(); - try { - IkeSecurityParameterIndex.allocateSecurityParameterIndex(LOCAL_ADDRESS, spiValue); - fail("Expected to fail because duplicate SPI was assigned to the same address."); - } catch (IOException expected) { - - } - - ikeSpiOne.close(); - IkeSecurityParameterIndex ikeSpiThree = - IkeSecurityParameterIndex.allocateSecurityParameterIndex(LOCAL_ADDRESS, spiValue); - ikeSpiThree.close(); - } - - private void setupFirstIkeSa() throws Exception { - // Inject IkeSaRecord and release IKE SPI resource since we will lose their references - // later. - when(mMockSaRecordHelper.makeFirstIkeSaRecord(any(), any(), any())) - .thenAnswer( - (invocation) -> { - captureAndReleaseIkeSpiResource(invocation, 2); - return mSpyCurrentIkeSaRecord; - }); - } - - private void setupRekeyedIkeSa(IkeSaRecord rekeySaRecord) throws Exception { - // Inject IkeSaRecord and release IKE SPI resource since we will lose their references - // later. - when(mMockSaRecordHelper.makeRekeyedIkeSaRecord( - eq(mSpyCurrentIkeSaRecord), any(), any(), any(), any())) - .thenAnswer( - (invocation) -> { - captureAndReleaseIkeSpiResource(invocation, 4); - return rekeySaRecord; - }); - } - - private void throwExceptionWhenMakeRekeyIkeSa(Exception exception) throws Exception { - // Inject IkeSaRecord and release IKE SPI resource since we will lose their references - // later. - when(mMockSaRecordHelper.makeRekeyedIkeSaRecord( - eq(mSpyCurrentIkeSaRecord), any(), any(), any(), any())) - .thenAnswer( - (invocation) -> { - captureAndReleaseIkeSpiResource(invocation, 4); - throw exception; - }); - } - - private void captureAndReleaseIkeSpiResource(InvocationOnMock invocation, int ikeConfigIndex) { - IkeSaRecordConfig config = (IkeSaRecordConfig) invocation.getArguments()[ikeConfigIndex]; - config.initSpi.close(); - config.respSpi.close(); - } - - @Test - public void testCreateIkeLocalIkeInit() throws Exception { - setupFirstIkeSa(); - - // Send IKE INIT request - mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.CMD_LOCAL_REQUEST_CREATE_IKE); - mLooper.dispatchAll(); - verifyRetransmissionStarted(); - - // Receive IKE INIT response - ReceivedIkePacket dummyReceivedIkePacket = makeIkeInitResponse(); - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, dummyReceivedIkePacket); - mLooper.dispatchAll(); - verifyIncrementLocaReqMsgId(); - - // Validate outbound IKE INIT request - verify(mMockIkeMessageHelper, times(2)).encode(mIkeMessageCaptor.capture()); - IkeMessage ikeInitReqMessage = mIkeMessageCaptor.getValue(); - - IkeHeader ikeHeader = ikeInitReqMessage.ikeHeader; - assertEquals(IkeHeader.EXCHANGE_TYPE_IKE_SA_INIT, ikeHeader.exchangeType); - assertFalse(ikeHeader.isResponseMsg); - assertTrue(ikeHeader.fromIkeInitiator); - - List<IkePayload> payloadList = ikeInitReqMessage.ikePayloadList; - assertTrue(isIkePayloadExist(payloadList, IkePayload.PAYLOAD_TYPE_SA)); - assertTrue(isIkePayloadExist(payloadList, IkePayload.PAYLOAD_TYPE_KE)); - assertTrue(isIkePayloadExist(payloadList, IkePayload.PAYLOAD_TYPE_NONCE)); - assertTrue(isNotifyExist(payloadList, NOTIFY_TYPE_NAT_DETECTION_SOURCE_IP)); - assertTrue(isNotifyExist(payloadList, NOTIFY_TYPE_NAT_DETECTION_DESTINATION_IP)); - assertTrue(isNotifyExist(payloadList, NOTIFY_TYPE_IKEV2_FRAGMENTATION_SUPPORTED)); - - verify(mSpyIkeSocket) - .registerIke(eq(mSpyCurrentIkeSaRecord.getLocalSpi()), eq(mIkeSessionStateMachine)); - - verify(mMockIkeMessageHelper) - .decode(0, dummyReceivedIkePacket.ikeHeader, dummyReceivedIkePacket.ikePacketBytes); - assertTrue( - mIkeSessionStateMachine.getCurrentState() - instanceof IkeSessionStateMachine.CreateIkeLocalIkeAuth); - verifyRetransmissionStarted(); - - // Validate negotiated SA proposal. - IkeSaProposal negotiatedProposal = mIkeSessionStateMachine.mSaProposal; - assertNotNull(negotiatedProposal); - - assertEquals( - new EncryptionTransform[] {mIkeEncryptionTransform}, - negotiatedProposal.getEncryptionTransforms()); - assertEquals( - new IntegrityTransform[] {mIkeIntegrityTransform}, - negotiatedProposal.getIntegrityTransforms()); - assertEquals(new PrfTransform[] {mIkePrfTransform}, negotiatedProposal.getPrfTransforms()); - - // Validate current IkeSaRecord. - verify(mMockSaRecordHelper) - .makeFirstIkeSaRecord( - any(IkeMessage.class), - any(IkeMessage.class), - mIkeSaRecordConfigCaptor.capture()); - - IkeSaRecordConfig ikeSaRecordConfig = mIkeSaRecordConfigCaptor.getValue(); - assertEquals(KEY_LEN_IKE_PRF, ikeSaRecordConfig.prf.getKeyLength()); - assertEquals(KEY_LEN_IKE_INTE, ikeSaRecordConfig.integrityKeyLength); - assertEquals(KEY_LEN_IKE_ENCR, ikeSaRecordConfig.encryptionKeyLength); - assertEquals(CMD_LOCAL_REQUEST_REKEY_IKE, ikeSaRecordConfig.futureRekeyEvent.procedureType); - - // Validate NAT detection - assertTrue(mIkeSessionStateMachine.mIsLocalBehindNat); - assertFalse(mIkeSessionStateMachine.mIsRemoteBehindNat); - - // Validate fragmentation support negotiation - assertTrue(mIkeSessionStateMachine.mSupportFragment); - } - - private void setIkeInitResults() throws Exception { - mIkeSessionStateMachine.mIkeCipher = mock(IkeCipher.class); - mIkeSessionStateMachine.mIkeIntegrity = mock(IkeMacIntegrity.class); - mIkeSessionStateMachine.mIkePrf = mock(IkeMacPrf.class); - mIkeSessionStateMachine.mSaProposal = buildSaProposal(); - mIkeSessionStateMachine.mCurrentIkeSaRecord = mSpyCurrentIkeSaRecord; - mIkeSessionStateMachine.mLocalAddress = LOCAL_ADDRESS; - mIkeSessionStateMachine.mIsLocalBehindNat = true; - mIkeSessionStateMachine.mIsRemoteBehindNat = false; - mIkeSessionStateMachine.mSupportFragment = true; - mIkeSessionStateMachine.addIkeSaRecord(mSpyCurrentIkeSaRecord); - } - - /** Initializes the mIkeSessionStateMachine in the IDLE state. */ - private void setupIdleStateMachine() throws Exception { - setIkeInitResults(); - - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_FORCE_TRANSITION, mIkeSessionStateMachine.mIdle); - mLooper.dispatchAll(); - - mDummyChildSmCallback = - createChildAndGetChildSessionSmCallback( - mMockChildSessionStateMachine, CHILD_SPI_REMOTE, mMockChildSessionCallback); - - assertTrue( - mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle); - } - - private void mockIkeInitAndTransitionToIkeAuth(State authState) throws Exception { - setIkeInitResults(); - - // Need to create a real IkeMacPrf instance for authentication because we cannot inject a - // method stub for IkeMacPrf#signBytes. IkeMacPrf#signBytes is inheritted from a package - // protected class IkePrf. We don't have the visibility to mock it. - mIkeSessionStateMachine.mIkePrf = - IkeMacPrf.create( - new PrfTransform(SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1), - IkeMessage.getSecurityProvider()); - - mIkeSessionStateMachine.mIkeInitRequestBytes = new byte[0]; - mIkeSessionStateMachine.mIkeInitResponseBytes = new byte[0]; - mIkeSessionStateMachine.mIkeInitNoncePayload = new IkeNoncePayload(); - mIkeSessionStateMachine.mIkeRespNoncePayload = new IkeNoncePayload(); - - mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.CMD_FORCE_TRANSITION, authState); - mLooper.dispatchAll(); - } - - private void setupChildStateMachineFactory(ChildSessionStateMachine child) { - // After state machine start, add to the callback->statemachine map - when(mMockChildSessionFactoryHelper.makeChildSessionStateMachine( - eq(mLooper.getLooper()), - eq(mContext), - eq(mChildSessionOptions), - eq(mSpyUserCbExecutor), - any(ChildSessionCallback.class), - any(IChildSessionSmCallback.class))) - .thenReturn(child); - } - - /** - * Utility to register a new callback -> state machine mapping. - * - * <p>Must be used if IkeSessionStateMachine.openChildSession() is not called, but commands - * injected instead. - * - * @param callback The callback to be used for the mapping - * @param sm The ChildSessionStateMachine instance to be used. - */ - private void registerChildStateMachine( - ChildSessionCallback callback, ChildSessionStateMachine sm) { - setupChildStateMachineFactory(sm); - mIkeSessionStateMachine.registerChildSessionCallback( - mChildSessionOptions, callback, false /*isFirstChild*/); - } - - @Test - public void testCreateAdditionalChild() throws Exception { - setupIdleStateMachine(); - - ChildSessionCallback childCallback = mock(ChildSessionCallback.class); - ChildSessionStateMachine childStateMachine = mock(ChildSessionStateMachine.class); - registerChildStateMachine(childCallback, childStateMachine); - - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ, - new ChildLocalRequest( - IkeSessionStateMachine.CMD_LOCAL_REQUEST_CREATE_CHILD, - childCallback, - mChildSessionOptions)); - mLooper.dispatchAll(); - - assertTrue( - mIkeSessionStateMachine.getCurrentState() - instanceof IkeSessionStateMachine.ChildProcedureOngoing); - verify(childStateMachine) - .createChildSession( - eq(LOCAL_ADDRESS), - eq(REMOTE_ADDRESS), - any(), // udpEncapSocket - eq(mIkeSessionStateMachine.mIkePrf), - any()); // sk_d - - // Once for initial child, a second time for the additional child. - verify(mMockChildSessionFactoryHelper) - .makeChildSessionStateMachine( - eq(mLooper.getLooper()), - eq(mContext), - eq(mChildSessionOptions), - eq(mSpyUserCbExecutor), - eq(childCallback), - mChildSessionSmCbCaptor.capture()); - IChildSessionSmCallback cb = mChildSessionSmCbCaptor.getValue(); - - // Mocking sending request - cb.onOutboundPayloadsReady( - IkeHeader.EXCHANGE_TYPE_CREATE_CHILD_SA, - false /*isResp*/, - new LinkedList<>(), - childStateMachine); - mLooper.dispatchAll(); - verifyRetransmissionStarted(); - - IkeMessage createChildRequest = verifyEncryptAndEncodeAndGetMessage(mSpyCurrentIkeSaRecord); - - IkeHeader ikeHeader = createChildRequest.ikeHeader; - assertEquals(IkeHeader.EXCHANGE_TYPE_CREATE_CHILD_SA, ikeHeader.exchangeType); - assertFalse(ikeHeader.isResponseMsg); - assertTrue(ikeHeader.fromIkeInitiator); - assertEquals(mSpyCurrentIkeSaRecord.getLocalRequestMessageId(), ikeHeader.messageId); - assertTrue(createChildRequest.ikePayloadList.isEmpty()); - - assertTrue( - mIkeSessionStateMachine.getCurrentState() - instanceof IkeSessionStateMachine.ChildProcedureOngoing); - - // Mocking receiving response - ReceivedIkePacket dummyCreateChildResp = makeCreateChildCreateMessage(true /*isResp*/); - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, dummyCreateChildResp); - mLooper.dispatchAll(); - - verifyIncrementLocaReqMsgId(); - verifyDecodeEncryptedMessage(mSpyCurrentIkeSaRecord, dummyCreateChildResp); - - verify(childStateMachine) - .receiveResponse( - eq(IkeHeader.EXCHANGE_TYPE_CREATE_CHILD_SA), mPayloadListCaptor.capture()); - - List<IkePayload> childRespList = mPayloadListCaptor.getValue(); - assertTrue(isIkePayloadExist(childRespList, IkePayload.PAYLOAD_TYPE_SA)); - assertTrue(isIkePayloadExist(childRespList, IkePayload.PAYLOAD_TYPE_TS_INITIATOR)); - assertTrue(isIkePayloadExist(childRespList, IkePayload.PAYLOAD_TYPE_TS_RESPONDER)); - assertTrue(isIkePayloadExist(childRespList, IkePayload.PAYLOAD_TYPE_NONCE)); - - // Mock finishing procedure - cb.onProcedureFinished(childStateMachine); - mLooper.dispatchAll(); - assertTrue( - mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle); - verifyRetransmissionStopped(); - } - - @Test - public void testTriggerDeleteChildLocal() throws Exception { - setupIdleStateMachine(); - - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ, - new ChildLocalRequest( - IkeSessionStateMachine.CMD_LOCAL_REQUEST_DELETE_CHILD, - mMockChildSessionCallback, - null /*childOptions*/)); - mLooper.dispatchAll(); - - assertTrue( - mIkeSessionStateMachine.getCurrentState() - instanceof IkeSessionStateMachine.ChildProcedureOngoing); - verify(mMockChildSessionStateMachine).deleteChildSession(); - } - - @Test - public void testHandleDeleteChildBeforeCreation() throws Exception { - setupIdleStateMachine(); - - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ, - new ChildLocalRequest( - IkeSessionStateMachine.CMD_LOCAL_REQUEST_DELETE_CHILD, - mock(ChildSessionCallback.class), - null /*childOptions*/)); - mLooper.dispatchAll(); - - assertTrue( - mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle); - } - - @Test - public void testTriggerRekeyChildLocal() throws Exception { - setupIdleStateMachine(); - - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ, - new ChildLocalRequest( - IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_CHILD, - mMockChildSessionCallback, - null /*childOptions*/)); - mLooper.dispatchAll(); - - assertTrue( - mIkeSessionStateMachine.getCurrentState() - instanceof IkeSessionStateMachine.ChildProcedureOngoing); - verify(mMockChildSessionStateMachine).rekeyChildSession(); - } - - @Test - public void testScheduleAndTriggerRekeyChildLocal() throws Exception { - setupIdleStateMachine(); - long dummyRekeyTimeout = 10000L; - - ChildLocalRequest rekeyRequest = - new ChildLocalRequest( - IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_CHILD, - mMockChildSessionCallback, - null /*childOptions*/); - mDummyChildSmCallback.scheduleLocalRequest(rekeyRequest, dummyRekeyTimeout); - - mLooper.moveTimeForward(dummyRekeyTimeout); - mLooper.dispatchAll(); - - assertTrue( - mIkeSessionStateMachine.getCurrentState() - instanceof IkeSessionStateMachine.ChildProcedureOngoing); - verify(mMockChildSessionStateMachine).rekeyChildSession(); - } - - private IChildSessionSmCallback createChildAndGetChildSessionSmCallback( - ChildSessionStateMachine child, int remoteSpi) throws Exception { - return createChildAndGetChildSessionSmCallback( - child, remoteSpi, mock(ChildSessionCallback.class)); - } - - private IChildSessionSmCallback createChildAndGetChildSessionSmCallback( - ChildSessionStateMachine child, int remoteSpi, ChildSessionCallback childCallback) - throws Exception { - registerChildStateMachine(childCallback, child); - - IChildSessionSmCallback cb = mIkeSessionStateMachine.new ChildSessionSmCallback(); - cb.onChildSaCreated(remoteSpi, child); - mLooper.dispatchAll(); - - return cb; - } - - private void transitionToChildProcedureOngoing() { - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_FORCE_TRANSITION, - mIkeSessionStateMachine.mChildProcedureOngoing); - mLooper.dispatchAll(); - assertTrue( - mIkeSessionStateMachine.getCurrentState() - instanceof IkeSessionStateMachine.ChildProcedureOngoing); - } - - private void verifyChildReceiveDeleteRequest( - ChildSessionStateMachine child, IkeDeletePayload[] expectedDelPayloads) { - verify(child) - .receiveRequest( - eq(IKE_EXCHANGE_SUBTYPE_DELETE_CHILD), - eq(EXCHANGE_TYPE_INFORMATIONAL), - mPayloadListCaptor.capture()); - List<IkePayload> reqPayloads = mPayloadListCaptor.getValue(); - - int numExpectedDelPayloads = expectedDelPayloads.length; - assertEquals(numExpectedDelPayloads, reqPayloads.size()); - - for (int i = 0; i < numExpectedDelPayloads; i++) { - assertEquals(expectedDelPayloads[i], (IkeDeletePayload) reqPayloads.get(i)); - } - } - - private void outboundDeleteChildPayloadsReady( - IChildSessionSmCallback childSmCb, - IkeDeletePayload delPayload, - boolean isResp, - ChildSessionStateMachine child) { - List<IkePayload> outPayloadList = new LinkedList<>(); - outPayloadList.add(delPayload); - childSmCb.onOutboundPayloadsReady( - IkeHeader.EXCHANGE_TYPE_INFORMATIONAL, isResp, outPayloadList, child); - mLooper.dispatchAll(); - } - - private List<IkePayload> verifyOutInfoMsgHeaderAndGetPayloads(boolean isResp) { - IkeMessage deleteChildMessage = verifyEncryptAndEncodeAndGetMessage(mSpyCurrentIkeSaRecord); - - IkeHeader ikeHeader = deleteChildMessage.ikeHeader; - assertEquals(mSpyCurrentIkeSaRecord.getInitiatorSpi(), ikeHeader.ikeInitiatorSpi); - assertEquals(mSpyCurrentIkeSaRecord.getResponderSpi(), ikeHeader.ikeResponderSpi); - assertEquals(IkePayload.PAYLOAD_TYPE_SK, ikeHeader.nextPayloadType); - assertEquals(IkeHeader.EXCHANGE_TYPE_INFORMATIONAL, ikeHeader.exchangeType); - assertEquals(mSpyCurrentIkeSaRecord.isLocalInit, ikeHeader.fromIkeInitiator); - assertEquals(isResp, ikeHeader.isResponseMsg); - - return deleteChildMessage.ikePayloadList; - } - - @Test - public void testDeferChildRequestToChildProcedureOngoing() throws Exception { - setupIdleStateMachine(); - - IkeDeletePayload[] inboundDelPayloads = - new IkeDeletePayload[] {new IkeDeletePayload(new int[] {CHILD_SPI_REMOTE})}; - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, - makeDeleteChildPacket(inboundDelPayloads, false /*isResp*/)); - mLooper.dispatchAll(); - - assertTrue( - mIkeSessionStateMachine.getCurrentState() - instanceof IkeSessionStateMachine.ChildProcedureOngoing); - verifyChildReceiveDeleteRequest(mMockChildSessionStateMachine, inboundDelPayloads); - } - - @Test - public void testRemoteDeleteOneChild() throws Exception { - setupIdleStateMachine(); - transitionToChildProcedureOngoing(); - - // Receive Delete Child Request - IkeDeletePayload[] inboundDelPayloads = - new IkeDeletePayload[] {new IkeDeletePayload(new int[] {CHILD_SPI_REMOTE})}; - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, - makeDeleteChildPacket(inboundDelPayloads, false /*isResp*/)); - mLooper.dispatchAll(); - - // Verify received payloads - verifyChildReceiveDeleteRequest(mMockChildSessionStateMachine, inboundDelPayloads); - - // Outbound payload list ready - IkeDeletePayload outDelPayload = new IkeDeletePayload(new int[] {CHILD_SPI_LOCAL}); - outboundDeleteChildPayloadsReady( - mDummyChildSmCallback, - outDelPayload, - true /*isResp*/, - mMockChildSessionStateMachine); - - // Verify outbound response - List<IkePayload> payloadList = verifyOutInfoMsgHeaderAndGetPayloads(true /*isResp*/); - assertEquals(1, payloadList.size()); - assertEquals(outDelPayload, ((IkeDeletePayload) payloadList.get(0))); - } - - @Test - public void testRemoteDeleteMultipleChildSession() throws Exception { - ChildSessionStateMachine childOne = mock(ChildSessionStateMachine.class); - int childOneRemoteSpi = 11; - int childOneLocalSpi = 12; - - ChildSessionStateMachine childTwo = mock(ChildSessionStateMachine.class); - int childTwoRemoteSpi = 21; - int childTwoLocalSpi = 22; - - setupIdleStateMachine(); - IChildSessionSmCallback childSmCbOne = - createChildAndGetChildSessionSmCallback(childOne, childOneRemoteSpi); - IChildSessionSmCallback childSmCbTwo = - createChildAndGetChildSessionSmCallback(childTwo, childTwoRemoteSpi); - - transitionToChildProcedureOngoing(); - - // Receive Delete Child Request - IkeDeletePayload[] inboundDelPayloads = - new IkeDeletePayload[] { - new IkeDeletePayload(new int[] {childOneRemoteSpi, childTwoRemoteSpi}) - }; - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, - makeDeleteChildPacket(inboundDelPayloads, false /*isResp*/)); - mLooper.dispatchAll(); - - // Verify received payloads - verifyChildReceiveDeleteRequest(childOne, inboundDelPayloads); - verifyChildReceiveDeleteRequest(childTwo, inboundDelPayloads); - - // childOne outbound payload list ready - IkeDeletePayload outDelPayloadOne = new IkeDeletePayload(new int[] {childOneLocalSpi}); - outboundDeleteChildPayloadsReady(childSmCbOne, outDelPayloadOne, true /*isResp*/, childOne); - mLooper.dispatchAll(); - - // Verify that no response is sent - verifyEncryptAndEncodeNeverCalled(mSpyCurrentIkeSaRecord); - - // childTwo outbound payload list ready - IkeDeletePayload outDelPayloadTwo = new IkeDeletePayload(new int[] {childTwoLocalSpi}); - outboundDeleteChildPayloadsReady(childSmCbTwo, outDelPayloadTwo, true /*isResp*/, childTwo); - mLooper.dispatchAll(); - - // Verify outbound response - List<IkePayload> payloadList = verifyOutInfoMsgHeaderAndGetPayloads(true /*isResp*/); - assertEquals(2, payloadList.size()); - assertEquals(outDelPayloadOne, ((IkeDeletePayload) payloadList.get(0))); - assertEquals(outDelPayloadTwo, ((IkeDeletePayload) payloadList.get(1))); - } - - @Test - public void testRemoteDeleteMultipleChildSaInSameSession() throws Exception { - int newChildRemoteSpi = 21; - int newChildLocalSpi = 22; - - setupIdleStateMachine(); - mDummyChildSmCallback.onChildSaCreated(newChildRemoteSpi, mMockChildSessionStateMachine); - - transitionToChildProcedureOngoing(); - - // Receive Delete Child Request - IkeDeletePayload[] inboundDelPayloads = - new IkeDeletePayload[] { - new IkeDeletePayload(new int[] {CHILD_SPI_REMOTE}), - new IkeDeletePayload(new int[] {newChildRemoteSpi}) - }; - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, - makeDeleteChildPacket(inboundDelPayloads, false /*isResp*/)); - mLooper.dispatchAll(); - - // Verify received payloads - verifyChildReceiveDeleteRequest(mMockChildSessionStateMachine, inboundDelPayloads); - - // child outbound payload list ready - IkeDeletePayload outDelPayload = - new IkeDeletePayload(new int[] {CHILD_SPI_LOCAL, newChildLocalSpi}); - outboundDeleteChildPayloadsReady( - mDummyChildSmCallback, - outDelPayload, - true /*isResp*/, - mMockChildSessionStateMachine); - mLooper.dispatchAll(); - - // Verify outbound response - List<IkePayload> payloadList = verifyOutInfoMsgHeaderAndGetPayloads(true /*isResp*/); - assertEquals(1, payloadList.size()); - assertEquals(outDelPayload, ((IkeDeletePayload) payloadList.get(0))); - } - - @Test - public void testIgnoreUnrecognizedChildSpi() throws Exception { - int unrecognizedSpi = 2; - - setupIdleStateMachine(); - transitionToChildProcedureOngoing(); - - // Receive Delete Child Request - IkeDeletePayload[] inboundDelPayloads = - new IkeDeletePayload[] { - new IkeDeletePayload(new int[] {unrecognizedSpi, CHILD_SPI_REMOTE}) - }; - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, - makeDeleteChildPacket(inboundDelPayloads, false /*isResp*/)); - mLooper.dispatchAll(); - - // Verify received payloads - verifyChildReceiveDeleteRequest(mMockChildSessionStateMachine, inboundDelPayloads); - - // child outbound payload list ready - IkeDeletePayload outPayload = new IkeDeletePayload(new int[] {CHILD_SPI_LOCAL}); - outboundDeleteChildPayloadsReady( - mDummyChildSmCallback, outPayload, true /*isResp*/, mMockChildSessionStateMachine); - mLooper.dispatchAll(); - - // Verify outbound response - List<IkePayload> payloadList = verifyOutInfoMsgHeaderAndGetPayloads(true /*isResp*/); - assertEquals(1, payloadList.size()); - assertEquals(outPayload, ((IkeDeletePayload) payloadList.get(0))); - } - - @Test - public void testRemoteDeleteChildHandlesReqWithNoRecognizedSpi() throws Exception { - int unrecognizedSpi = 2; - - setupIdleStateMachine(); - - // Receive Delete Child Request without any recognized SPI - IkeDeletePayload[] inboundDelPayloads = - new IkeDeletePayload[] {new IkeDeletePayload(new int[] {unrecognizedSpi})}; - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, - makeDeleteChildPacket(inboundDelPayloads, false /*isResp*/)); - mLooper.dispatchAll(); - - // Verify outbound empty response was sent - List<IkePayload> payloadList = verifyOutInfoMsgHeaderAndGetPayloads(true /*isResp*/); - assertTrue(payloadList.isEmpty()); - - // Verify IKE Session was back to Idle - assertTrue( - mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle); - } - - @Test - public void testRemoteCreateChild() throws Exception { - setupIdleStateMachine(); - - mIkeSessionStateMachine.sendMessage( - CMD_RECEIVE_IKE_PACKET, makeCreateChildCreateMessage(false /*isResp*/)); - - mLooper.dispatchAll(); - - assertTrue( - mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle); - - List<IkePayload> ikePayloadList = verifyOutInfoMsgHeaderAndGetPayloads(true /*isResp*/); - assertEquals(1, ikePayloadList.size()); - assertEquals( - ERROR_TYPE_NO_ADDITIONAL_SAS, - ((IkeNotifyPayload) ikePayloadList.get(0)).notifyType); - } - - @Test - public void testTriggerRemoteRekeyChild() throws Exception { - setupIdleStateMachine(); - - mIkeSessionStateMachine.sendMessage( - CMD_RECEIVE_IKE_PACKET, - makeRekeyChildCreateMessage(false /*isResp*/, CHILD_SPI_REMOTE)); - mLooper.dispatchAll(); - - verify(mMockChildSessionStateMachine) - .receiveRequest( - eq(IKE_EXCHANGE_SUBTYPE_REKEY_CHILD), - eq(EXCHANGE_TYPE_CREATE_CHILD_SA), - any(List.class)); - assertTrue( - mIkeSessionStateMachine.getCurrentState() - instanceof IkeSessionStateMachine.ChildProcedureOngoing); - } - - @Test - public void testHandleRekeyChildReqWithUnrecognizedSpi() throws Exception { - int unrecognizedSpi = 2; - - setupIdleStateMachine(); - - mIkeSessionStateMachine.sendMessage( - CMD_RECEIVE_IKE_PACKET, - makeRekeyChildCreateMessage(false /*isResp*/, unrecognizedSpi)); - mLooper.dispatchAll(); - - verify(mMockChildSessionStateMachine, never()).receiveRequest(anyInt(), anyInt(), any()); - assertTrue( - mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle); - - List<IkePayload> ikePayloadList = verifyOutInfoMsgHeaderAndGetPayloads(true /*isResp*/); - assertEquals(1, ikePayloadList.size()); - IkeNotifyPayload notifyPayload = (IkeNotifyPayload) ikePayloadList.get(0); - assertEquals(ERROR_TYPE_CHILD_SA_NOT_FOUND, notifyPayload.notifyType); - assertEquals(unrecognizedSpi, notifyPayload.spi); - } - - private void verifyNotifyUserCloseSession() { - verify(mSpyUserCbExecutor).execute(any(Runnable.class)); - verify(mMockIkeSessionCallback).onClosed(); - } - - @Test - public void testRcvRemoteDeleteIkeWhenChildProcedureOngoing() throws Exception { - setupIdleStateMachine(); - transitionToChildProcedureOngoing(); - - mIkeSessionStateMachine.sendMessage( - CMD_RECEIVE_IKE_PACKET, makeDeleteIkeRequest(mSpyCurrentIkeSaRecord)); - - mLooper.dispatchAll(); - - verifyNotifyUserCloseSession(); - - // Verify state machine quit properly - assertNull(mIkeSessionStateMachine.getCurrentState()); - - List<IkePayload> ikePayloadList = verifyOutInfoMsgHeaderAndGetPayloads(true /*isResp*/); - assertTrue(ikePayloadList.isEmpty()); - } - - @Test - public void testRcvRemoteRekeyIkeWhenChildProcedureOngoing() throws Exception { - setupIdleStateMachine(); - transitionToChildProcedureOngoing(); - - mIkeSessionStateMachine.sendMessage(CMD_RECEIVE_IKE_PACKET, makeRekeyIkeRequest()); - - mLooper.dispatchAll(); - - // Since we have forced state machine to transition to ChildProcedureOngoing state without - // really starting any Child procedure, it should transition to Idle at this time. - assertTrue( - mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle); - - List<IkePayload> ikePayloadList = verifyOutInfoMsgHeaderAndGetPayloads(true /*isResp*/); - assertEquals(1, ikePayloadList.size()); - assertEquals( - ERROR_TYPE_TEMPORARY_FAILURE, - ((IkeNotifyPayload) ikePayloadList.get(0)).notifyType); - } - - @Test - public void testKillChildSessions() throws Exception { - setupIdleStateMachine(); - - ChildSessionStateMachine childOne = mock(ChildSessionStateMachine.class); - ChildSessionStateMachine childTwo = mock(ChildSessionStateMachine.class); - registerChildStateMachine(mock(ChildSessionCallback.class), childOne); - registerChildStateMachine(mock(ChildSessionCallback.class), childTwo); - - mIkeSessionStateMachine.mCurrentIkeSaRecord = null; - - mIkeSessionStateMachine.quitNow(); - - mLooper.dispatchAll(); - - verify(childOne).killSession(); - verify(childTwo).killSession(); - } - - private IkeMessage verifyAuthReqAndGetMsg() { - IkeMessage ikeAuthReqMessage = verifyEncryptAndEncodeAndGetMessage(mSpyCurrentIkeSaRecord); - - IkeHeader ikeHeader = ikeAuthReqMessage.ikeHeader; - assertEquals(IkeHeader.EXCHANGE_TYPE_IKE_AUTH, ikeHeader.exchangeType); - assertFalse(ikeHeader.isResponseMsg); - assertTrue(ikeHeader.fromIkeInitiator); - - return ikeAuthReqMessage; - } - - private IkeMessage verifyAuthReqWithChildPayloadsAndGetMsg() { - IkeMessage ikeAuthReqMessage = verifyAuthReqAndGetMsg(); - - assertNotNull( - ikeAuthReqMessage.getPayloadForType( - IkePayload.PAYLOAD_TYPE_ID_INITIATOR, IkeIdPayload.class)); - assertNotNull( - ikeAuthReqMessage.getPayloadForType( - IkePayload.PAYLOAD_TYPE_ID_RESPONDER, IkeIdPayload.class)); - assertNotNull( - ikeAuthReqMessage.getPayloadForType( - IkePayload.PAYLOAD_TYPE_SA, IkeSaPayload.class)); - assertNotNull( - ikeAuthReqMessage.getPayloadForType( - IkePayload.PAYLOAD_TYPE_TS_INITIATOR, IkeTsPayload.class)); - assertNotNull( - ikeAuthReqMessage.getPayloadForType( - IkePayload.PAYLOAD_TYPE_TS_RESPONDER, IkeTsPayload.class)); - - return ikeAuthReqMessage; - } - - private void verifySharedKeyAuthentication( - IkeAuthPskPayload spyAuthPayload, - IkeIdPayload respIdPayload, - List<IkePayload> authRelatedPayloads, - boolean hasChildPayloads) - throws Exception { - // Send IKE AUTH response to IKE state machine - ReceivedIkePacket authResp = makeIkeAuthRespWithChildPayloads(authRelatedPayloads); - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, authResp); - mLooper.dispatchAll(); - - // Validate outbound IKE AUTH request - IkeMessage ikeAuthReqMessage; - if (hasChildPayloads) { - ikeAuthReqMessage = verifyAuthReqWithChildPayloadsAndGetMsg(); - } else { - ikeAuthReqMessage = verifyAuthReqAndGetMsg(); - } - assertNotNull( - ikeAuthReqMessage.getPayloadForType( - IkePayload.PAYLOAD_TYPE_AUTH, IkeAuthPskPayload.class)); - - // Validate inbound IKE AUTH response - verifyIncrementLocaReqMsgId(); - verifyDecodeEncryptedMessage(mSpyCurrentIkeSaRecord, authResp); - - // Validate authentication is done. Cannot use matchers because IkeAuthPskPayload is final. - verify(spyAuthPayload) - .verifyInboundSignature( - mPsk, - mIkeSessionStateMachine.mIkeInitRequestBytes, - mSpyCurrentIkeSaRecord.nonceInitiator, - respIdPayload.getEncodedPayloadBody(), - mIkeSessionStateMachine.mIkePrf, - mSpyCurrentIkeSaRecord.getSkPr()); - - // Validate that user has been notified - verify(mSpyUserCbExecutor).execute(any(Runnable.class)); - verify(mMockIkeSessionCallback).onOpened(any()); - // TODO: Verify sessionConfiguration - - // Verify payload list pair for first Child negotiation - ArgumentCaptor<List<IkePayload>> mReqPayloadListCaptor = - ArgumentCaptor.forClass(List.class); - ArgumentCaptor<List<IkePayload>> mRespPayloadListCaptor = - ArgumentCaptor.forClass(List.class); - verify(mMockChildSessionStateMachine) - .handleFirstChildExchange( - mReqPayloadListCaptor.capture(), - mRespPayloadListCaptor.capture(), - eq(LOCAL_ADDRESS), - eq(REMOTE_ADDRESS), - any(), // udpEncapSocket - eq(mIkeSessionStateMachine.mIkePrf), - any()); // sk_d - List<IkePayload> childReqList = mReqPayloadListCaptor.getValue(); - List<IkePayload> childRespList = mRespPayloadListCaptor.getValue(); - - assertTrue(isIkePayloadExist(childReqList, IkePayload.PAYLOAD_TYPE_SA)); - assertTrue(isIkePayloadExist(childReqList, IkePayload.PAYLOAD_TYPE_TS_INITIATOR)); - assertTrue(isIkePayloadExist(childReqList, IkePayload.PAYLOAD_TYPE_TS_RESPONDER)); - assertTrue(isIkePayloadExist(childReqList, IkePayload.PAYLOAD_TYPE_NONCE)); - IkeSaPayload reqSaPayload = - IkePayload.getPayloadForTypeInProvidedList( - IkePayload.PAYLOAD_TYPE_SA, IkeSaPayload.class, childReqList); - assertFalse(reqSaPayload.isSaResponse); - - assertTrue(isIkePayloadExist(childRespList, IkePayload.PAYLOAD_TYPE_SA)); - assertTrue(isIkePayloadExist(childRespList, IkePayload.PAYLOAD_TYPE_TS_INITIATOR)); - assertTrue(isIkePayloadExist(childRespList, IkePayload.PAYLOAD_TYPE_TS_RESPONDER)); - assertTrue(isIkePayloadExist(childRespList, IkePayload.PAYLOAD_TYPE_NONCE)); - IkeSaPayload respSaPayload = - IkePayload.getPayloadForTypeInProvidedList( - IkePayload.PAYLOAD_TYPE_SA, IkeSaPayload.class, childRespList); - assertTrue(respSaPayload.isSaResponse); - - // Mock finishing first Child SA negotiation. - assertTrue( - mIkeSessionStateMachine.getCurrentState() - instanceof IkeSessionStateMachine.ChildProcedureOngoing); - - verify(mMockChildSessionFactoryHelper) - .makeChildSessionStateMachine( - eq(mLooper.getLooper()), - eq(mContext), - eq(mChildSessionOptions), - eq(mSpyUserCbExecutor), - eq(mMockChildSessionCallback), - mChildSessionSmCbCaptor.capture()); - IChildSessionSmCallback cb = mChildSessionSmCbCaptor.getValue(); - - cb.onProcedureFinished(mMockChildSessionStateMachine); - mLooper.dispatchAll(); - assertTrue( - mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle); - } - - private IkeAuthPskPayload makeSpyRespPskPayload() throws Exception { - IkeAuthPskPayload spyAuthPayload = - spy( - (IkeAuthPskPayload) - IkeTestUtils.hexStringToIkePayload( - IkePayload.PAYLOAD_TYPE_AUTH, - true /*isResp*/, - PSK_AUTH_RESP_PAYLOAD_HEX_STRING)); - - doNothing() - .when(spyAuthPayload) - .verifyInboundSignature(any(), any(), any(), any(), any(), any()); - return spyAuthPayload; - } - - private IkeAuthDigitalSignPayload makeSpyDigitalSignAuthPayload() throws Exception { - IkeAuthDigitalSignPayload spyAuthPayload = - spy( - (IkeAuthDigitalSignPayload) - IkeTestUtils.hexStringToIkePayload( - IkePayload.PAYLOAD_TYPE_AUTH, - true /*isResp*/, - GENERIC_DIGITAL_SIGN_AUTH_RESP_HEX_STRING)); - doNothing() - .when(spyAuthPayload) - .verifyInboundSignature(any(), any(), any(), any(), any(), any()); - return spyAuthPayload; - } - - private IkeIdPayload makeRespIdPayload() throws Exception { - return (IkeIdPayload) - IkeTestUtils.hexStringToIkePayload( - IkePayload.PAYLOAD_TYPE_ID_RESPONDER, - true /*isResp*/, - ID_PAYLOAD_RESPONDER_HEX_STRING); - } - - @Test - public void testCreateIkeLocalIkeAuthPsk() throws Exception { - mockIkeInitAndTransitionToIkeAuth(mIkeSessionStateMachine.mCreateIkeLocalIkeAuth); - verifyRetransmissionStarted(); - - // Build IKE AUTH response with Auth-PSK Payload and ID-Responder Payload. - List<IkePayload> authRelatedPayloads = new LinkedList<>(); - IkeAuthPskPayload spyAuthPayload = makeSpyRespPskPayload(); - authRelatedPayloads.add(spyAuthPayload); - - IkeIdPayload respIdPayload = makeRespIdPayload(); - authRelatedPayloads.add(respIdPayload); - - verifySharedKeyAuthentication(spyAuthPayload, respIdPayload, authRelatedPayloads, true); - verifyRetransmissionStopped(); - } - - @Test - public void testCreateIkeLocalIkeAuthPskVerifyFail() throws Exception { - mockIkeInitAndTransitionToIkeAuth(mIkeSessionStateMachine.mCreateIkeLocalIkeAuth); - verifyRetransmissionStarted(); - resetMockIkeMessageHelper(); - - // Build IKE AUTH response with invalid Auth-PSK Payload and ID-Responder Payload. - List<IkePayload> authRelatedPayloads = new LinkedList<>(); - IkeAuthPskPayload spyAuthPayload = makeSpyRespPskPayload(); - doThrow(new AuthenticationFailedException("DummyAuthFailException")) - .when(spyAuthPayload) - .verifyInboundSignature(any(), any(), any(), any(), any(), any()); - authRelatedPayloads.add(spyAuthPayload); - - IkeIdPayload respIdPayload = makeRespIdPayload(); - authRelatedPayloads.add(respIdPayload); - - // Send response to IKE state machine - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, - makeIkeAuthRespWithChildPayloads(authRelatedPayloads)); - mLooper.dispatchAll(); - - // Verify Delete request was sent - List<IkePayload> payloads = verifyOutInfoMsgHeaderAndGetPayloads(false /*isResp*/); - assertEquals(1, payloads.size()); - assertEquals(IkePayload.PAYLOAD_TYPE_DELETE, payloads.get(0).payloadType); - - // Verify IKE Session was closed properly - assertNull(mIkeSessionStateMachine.getCurrentState()); - verify(mMockIkeSessionCallback) - .onClosedExceptionally(any(AuthenticationFailedException.class)); - } - - @Test - public void testAuthPskHandleRespWithParsingError() throws Exception { - mockIkeInitAndTransitionToIkeAuth(mIkeSessionStateMachine.mCreateIkeLocalIkeAuth); - verifyRetransmissionStarted(); - resetMockIkeMessageHelper(); - - // Mock receiving packet with syntax error - ReceivedIkePacket mockInvalidPacket = - makeDummyReceivedIkePacketWithInvalidSyntax( - mSpyCurrentIkeSaRecord, true /*isResp*/, IkeHeader.EXCHANGE_TYPE_IKE_AUTH); - mIkeSessionStateMachine.sendMessage(CMD_RECEIVE_IKE_PACKET, mockInvalidPacket); - mLooper.dispatchAll(); - - // Verify Delete request was sent - List<IkePayload> payloads = verifyOutInfoMsgHeaderAndGetPayloads(false /*isResp*/); - assertEquals(1, payloads.size()); - assertEquals(IkePayload.PAYLOAD_TYPE_DELETE, payloads.get(0).payloadType); - - // Verify IKE Session is closed properly - assertNull(mIkeSessionStateMachine.getCurrentState()); - verify(mMockIkeSessionCallback).onClosedExceptionally(any(InvalidSyntaxException.class)); - } - - @Test - public void testCreateIkeLocalIkeAuthPreEap() throws Exception { - mIkeSessionStateMachine.quitNow(); - mIkeSessionStateMachine = makeAndStartIkeSession(buildIkeSessionOptionsEap()); - - // Mock IKE INIT - mockIkeInitAndTransitionToIkeAuth(mIkeSessionStateMachine.mCreateIkeLocalIkeAuth); - verifyRetransmissionStarted(); - - // Build IKE AUTH response with EAP. Auth, ID-Resp and Cert payloads. - List<IkePayload> authRelatedPayloads = new LinkedList<>(); - - authRelatedPayloads.add(new IkeEapPayload(EAP_DUMMY_MSG)); - authRelatedPayloads.add(makeSpyDigitalSignAuthPayload()); - authRelatedPayloads.add(makeRespIdPayload()); - - IkeCertX509CertPayload certPayload = new IkeCertX509CertPayload(mServerEndCertificate); - authRelatedPayloads.add(certPayload); - - // Send IKE AUTH response to IKE state machine - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, - makeIkeAuthRespWithoutChildPayloads(authRelatedPayloads)); - mLooper.dispatchAll(); - - // Validate outbound IKE AUTH request - IkeMessage ikeAuthReqMessage = verifyAuthReqWithChildPayloadsAndGetMsg(); - assertNull( - ikeAuthReqMessage.getPayloadForType( - IkePayload.PAYLOAD_TYPE_AUTH, IkeAuthPayload.class)); - - assertTrue( - mIkeSessionStateMachine.getCurrentState() - instanceof IkeSessionStateMachine.CreateIkeLocalIkeAuthInEap); - verifyRetransmissionStopped(); - assertNotNull(mIkeSessionStateMachine.mInitIdPayload); - assertNotNull(mIkeSessionStateMachine.mRespIdPayload); - } - - private IEapCallback verifyEapAuthenticatorCreatedAndGetCallback() { - ArgumentCaptor<IEapCallback> captor = ArgumentCaptor.forClass(IEapCallback.class); - - verify(mMockEapAuthenticatorFactory) - .newEapAuthenticator( - eq(mIkeSessionStateMachine.getHandler().getLooper()), - captor.capture(), - eq(mContext), - eq(mEapSessionConfig)); - - return captor.getValue(); - } - - @Test - public void testCreateIkeLocalIkeAuthInEapStartsAuthenticatorAndProxiesMessage() - throws Exception { - mIkeSessionStateMachine.quitNow(); - mIkeSessionStateMachine = makeAndStartIkeSession(buildIkeSessionOptionsEap()); - - // Setup state and go to IN_EAP state - mockIkeInitAndTransitionToIkeAuth(mIkeSessionStateMachine.mCreateIkeLocalIkeAuthInEap); - mLooper.dispatchAll(); - - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_EAP_START_EAP_AUTH, new IkeEapPayload(EAP_DUMMY_MSG)); - mLooper.dispatchAll(); - - verifyEapAuthenticatorCreatedAndGetCallback(); - - verify(mMockEapAuthenticator).processEapMessage(eq(EAP_DUMMY_MSG)); - } - - @Test - public void testCreateIkeLocalIkeAuthInEapHandlesOutboundResponse() throws Exception { - mIkeSessionStateMachine.quitNow(); - mIkeSessionStateMachine = makeAndStartIkeSession(buildIkeSessionOptionsEap()); - - // Setup state and go to IN_EAP state - mockIkeInitAndTransitionToIkeAuth(mIkeSessionStateMachine.mCreateIkeLocalIkeAuthInEap); - mLooper.dispatchAll(); - - IEapCallback callback = verifyEapAuthenticatorCreatedAndGetCallback(); - callback.onResponse(EAP_DUMMY_MSG); - mLooper.dispatchAll(); - verifyRetransmissionStarted(); - - // Verify EAP response - IkeMessage resp = verifyEncryptAndEncodeAndGetMessage(mSpyCurrentIkeSaRecord); - IkeHeader ikeHeader = resp.ikeHeader; - assertEquals(IkePayload.PAYLOAD_TYPE_SK, ikeHeader.nextPayloadType); - assertEquals(IkeHeader.EXCHANGE_TYPE_IKE_AUTH, ikeHeader.exchangeType); - assertFalse(ikeHeader.isResponseMsg); - assertEquals(mSpyCurrentIkeSaRecord.isLocalInit, ikeHeader.fromIkeInitiator); - - assertEquals(1, resp.ikePayloadList.size()); - assertArrayEquals(EAP_DUMMY_MSG, ((IkeEapPayload) resp.ikePayloadList.get(0)).eapMessage); - } - - @Test - public void testCreateIkeLocalIkeAuthInEapHandlesMissingEapPacket() throws Exception { - mIkeSessionStateMachine.quitNow(); - mIkeSessionStateMachine = makeAndStartIkeSession(buildIkeSessionOptionsEap()); - - // Setup state and go to IN_EAP state - mockIkeInitAndTransitionToIkeAuth(mIkeSessionStateMachine.mCreateIkeLocalIkeAuthInEap); - mLooper.dispatchAll(); - - // Mock sending IKE_AUTH{EAP} request - IEapCallback callback = verifyEapAuthenticatorCreatedAndGetCallback(); - callback.onResponse(EAP_DUMMY_MSG); - mLooper.dispatchAll(); - verifyRetransmissionStarted(); - - // Send IKE AUTH response with no EAP Payload to IKE state machine - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, - makeIkeAuthRespWithoutChildPayloads(new LinkedList<>())); - mLooper.dispatchAll(); - - // Verify state machine quit properly - verify(mMockIkeSessionCallback) - .onClosedExceptionally(any(AuthenticationFailedException.class)); - assertNull(mIkeSessionStateMachine.getCurrentState()); - } - - @Test - public void testCreateIkeLocalIkeAuthInEapHandlesSuccess() throws Exception { - mIkeSessionStateMachine.quitNow(); - mIkeSessionStateMachine = makeAndStartIkeSession(buildIkeSessionOptionsEap()); - - // Setup state and go to IN_EAP state - mockIkeInitAndTransitionToIkeAuth(mIkeSessionStateMachine.mCreateIkeLocalIkeAuthInEap); - mLooper.dispatchAll(); - - IEapCallback callback = verifyEapAuthenticatorCreatedAndGetCallback(); - - // Setup dummy initIdPayload for next state. - mIkeSessionStateMachine.mInitIdPayload = mock(IkeIdPayload.class); - when(mIkeSessionStateMachine.mInitIdPayload.getEncodedPayloadBody()) - .thenReturn(new byte[0]); - - callback.onSuccess(mPsk, new byte[0]); // use mPsk as MSK, eMSK does not matter - mLooper.dispatchAll(); - - assertTrue( - mIkeSessionStateMachine.getCurrentState() - instanceof IkeSessionStateMachine.CreateIkeLocalIkeAuthPostEap); - } - - @Test - public void testCreateIkeLocalIkeAuthInEapHandlesError() throws Exception { - mIkeSessionStateMachine.quitNow(); - mIkeSessionStateMachine = makeAndStartIkeSession(buildIkeSessionOptionsEap()); - - // Setup state and go to IN_EAP state - mockIkeInitAndTransitionToIkeAuth(mIkeSessionStateMachine.mCreateIkeLocalIkeAuthInEap); - mLooper.dispatchAll(); - - IEapCallback callback = verifyEapAuthenticatorCreatedAndGetCallback(); - - Throwable error = new IllegalArgumentException(); - callback.onError(error); - mLooper.dispatchAll(); - - // Fires user error callbacks - verify(mMockIkeSessionCallback) - .onClosedExceptionally(argThat(err -> err.getCause() == error)); - - // Verify state machine quit properly - verify(mSpyCurrentIkeSaRecord).close(); - assertNull(mIkeSessionStateMachine.getCurrentState()); - } - - @Test - public void testCreateIkeLocalIkeAuthInEapHandlesFailure() throws Exception { - mIkeSessionStateMachine.quitNow(); - mIkeSessionStateMachine = makeAndStartIkeSession(buildIkeSessionOptionsEap()); - - // Setup state and go to IN_EAP state - mockIkeInitAndTransitionToIkeAuth(mIkeSessionStateMachine.mCreateIkeLocalIkeAuthInEap); - mLooper.dispatchAll(); - - IEapCallback callback = verifyEapAuthenticatorCreatedAndGetCallback(); - callback.onFail(); - mLooper.dispatchAll(); - - // Fires user error callbacks - verify(mMockIkeSessionCallback) - .onClosedExceptionally(any(AuthenticationFailedException.class)); - - // Verify state machine quit properly - verify(mSpyCurrentIkeSaRecord).close(); - assertNull(mIkeSessionStateMachine.getCurrentState()); - } - - @Test - public void testCreateIkeLocalIkeAuthPostEap() throws Exception { - mIkeSessionStateMachine.quitNow(); - reset(mMockChildSessionFactoryHelper); - setupChildStateMachineFactory(mMockChildSessionStateMachine); - mIkeSessionStateMachine = makeAndStartIkeSession(buildIkeSessionOptionsEap()); - - // Setup dummy state from IkeAuthPreEap for next state. - mIkeSessionStateMachine.mInitIdPayload = mock(IkeIdPayload.class); - when(mIkeSessionStateMachine.mInitIdPayload.getEncodedPayloadBody()) - .thenReturn(new byte[0]); - mIkeSessionStateMachine.mRespIdPayload = - (IkeIdPayload) - IkeTestUtils.hexStringToIkePayload( - IkePayload.PAYLOAD_TYPE_ID_RESPONDER, - true /*isResp*/, - ID_PAYLOAD_RESPONDER_HEX_STRING); - - List<Integer> payloadTypeList = new LinkedList<>(); - List<String> payloadHexStringList = new LinkedList<>(); - - payloadTypeList.add(IkePayload.PAYLOAD_TYPE_SA); - payloadTypeList.add(IkePayload.PAYLOAD_TYPE_TS_INITIATOR); - payloadTypeList.add(IkePayload.PAYLOAD_TYPE_TS_RESPONDER); - - payloadHexStringList.add(CHILD_SA_PAYLOAD_HEX_STRING); - payloadHexStringList.add(TS_INIT_PAYLOAD_HEX_STRING); - payloadHexStringList.add(TS_RESP_PAYLOAD_HEX_STRING); - - mIkeSessionStateMachine.mFirstChildReqList = - hexStrListToIkePayloadList(payloadTypeList, payloadHexStringList, false /*isResp*/); - - // Setup state and go to IN_EAP state - mockIkeInitAndTransitionToIkeAuth(mIkeSessionStateMachine.mCreateIkeLocalIkeAuthPostEap); - mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.CMD_EAP_FINISH_EAP_AUTH, mPsk); - mLooper.dispatchAll(); - verifyRetransmissionStarted(); - - // Build IKE AUTH response with Auth-PSK Payload and ID-Responder Payload. - List<IkePayload> authRelatedPayloads = new LinkedList<>(); - IkeAuthPskPayload spyAuthPayload = makeSpyRespPskPayload(); - authRelatedPayloads.add(spyAuthPayload); - - IkeIdPayload respIdPayload = makeRespIdPayload(); - - verifySharedKeyAuthentication(spyAuthPayload, respIdPayload, authRelatedPayloads, false); - verifyRetransmissionStopped(); - } - - @Test - public void testCreateIkeLocalIkeAuthHandlesFirstFrag() throws Exception { - mockIkeInitAndTransitionToIkeAuth(mIkeSessionStateMachine.mCreateIkeLocalIkeAuth); - verifyRetransmissionStarted(); - - // Received IKE fragment - byte[] unencryptedData = "testCreateIkeLocalIkeAuthHandlesFrag".getBytes(); - int fragNum = 1; - int totalFragments = 2; - IkeSkfPayload skfPayload = - IkeTestUtils.makeDummySkfPayload(unencryptedData, fragNum, totalFragments); - - ReceivedIkePacket packet = - makeDummyReceivedIkeFragmentPacket( - mSpyCurrentIkeSaRecord, - true /*isResp*/, - IkeHeader.EXCHANGE_TYPE_IKE_AUTH, - skfPayload, - PAYLOAD_TYPE_AUTH, - null /* collectedFrags*/); - mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, packet); - mLooper.dispatchAll(); - - // Verify state doesn't change - assertTrue( - mIkeSessionStateMachine.getCurrentState() - instanceof IkeSessionStateMachine.CreateIkeLocalIkeAuth); - - // Verify the IkeSaRecord has stored the fragment. - DecodeResultPartial resultPartial = - mSpyCurrentIkeSaRecord.getCollectedFragments(true /*isResp*/); - assertEquals(PAYLOAD_TYPE_AUTH, resultPartial.firstPayloadType); - assertEquals(totalFragments, resultPartial.collectedFragsList.length); - assertArrayEquals(unencryptedData, resultPartial.collectedFragsList[fragNum - 1]); - assertFalse(resultPartial.isAllFragmentsReceived()); - - assertNull(mSpyCurrentIkeSaRecord.getCollectedFragments(false /*isResp*/)); - } - - @Test - public void testCreateIkeLocalIkeAuthHandlesLastFragOk() throws Exception { - mockIkeInitAndTransitionToIkeAuth(mIkeSessionStateMachine.mCreateIkeLocalIkeAuth); - verifyRetransmissionStarted(); - - // Set previously collected IKE fragments - DecodeResultPartial mockCollectedFrags = mock(DecodeResultPartial.class); - mSpyCurrentIkeSaRecord.updateCollectedFragments(mockCollectedFrags, true /*isResp*/); - - // Build reassembled IKE AUTH response with Auth-PSK Payload and ID-Responder Payload. - List<IkePayload> authRelatedPayloads = new LinkedList<>(); - IkeAuthPskPayload spyAuthPayload = makeSpyRespPskPayload(); - authRelatedPayloads.add(spyAuthPayload); - - IkeIdPayload respIdPayload = makeRespIdPayload(); - authRelatedPayloads.add(respIdPayload); - - List<IkePayload> authPayloadList = - getIkeAuthPayloadListWithChildPayloads(authRelatedPayloads); - - // Receive last auth response and do IKE_AUTH - ReceivedIkePacket packet = - makeDummyReceivedLastIkeFragmentPacketOk( - mSpyCurrentIkeSaRecord, - true /*isResp*/, - IkeHeader.EXCHANGE_TYPE_IKE_AUTH, - mockCollectedFrags, - authPayloadList, - "FirstFrag".getBytes()); - mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, packet); - mLooper.dispatchAll(); - - // Verify IKE AUTH is done - assertTrue( - mIkeSessionStateMachine.getCurrentState() - instanceof IkeSessionStateMachine.ChildProcedureOngoing); - - // Verify collected response fragments are cleared. - assertNull(mSpyCurrentIkeSaRecord.getCollectedFragments(true /*isResp*/)); - verify(mSpyCurrentIkeSaRecord).resetCollectedFragments(true /*isResp*/); - } - - @Test - public void testCreateIkeLocalIkeAuthHandlesLastFragError() throws Exception { - mockIkeInitAndTransitionToIkeAuth(mIkeSessionStateMachine.mCreateIkeLocalIkeAuth); - verifyRetransmissionStarted(); - resetMockIkeMessageHelper(); - - // Set previously collected IKE fragments - DecodeResultPartial mockCollectedFrags = mock(DecodeResultPartial.class); - mSpyCurrentIkeSaRecord.updateCollectedFragments(mockCollectedFrags, true /*isResp*/); - - // Receive last auth response with syntax error - ReceivedIkePacket packet = - makeDummyReceivedLastIkeFragmentPacketError( - mSpyCurrentIkeSaRecord, - true /*isResp*/, - IkeHeader.EXCHANGE_TYPE_IKE_AUTH, - mockCollectedFrags, - new InvalidSyntaxException("IkeStateMachineTest")); - mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, packet); - mLooper.dispatchAll(); - - // Verify Delete request is sent - List<IkePayload> payloads = verifyOutInfoMsgHeaderAndGetPayloads(false /*isResp*/); - assertEquals(1, payloads.size()); - assertEquals(IkePayload.PAYLOAD_TYPE_DELETE, payloads.get(0).payloadType); - - // Verify IKE Session is closed properly - assertNull(mIkeSessionStateMachine.getCurrentState()); - verify(mMockIkeSessionCallback).onClosedExceptionally(any(InvalidSyntaxException.class)); - - // Collected response fragments are cleared - assertNull(mSpyCurrentIkeSaRecord.getCollectedFragments(true /*isResp*/)); - verify(mSpyCurrentIkeSaRecord).resetCollectedFragments(true /*isResp*/); - } - - @Test - public void testRekeyIkeLocalCreateSendsRequest() throws Exception { - setupIdleStateMachine(); - - // Send Rekey-Create request - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ, - new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE)); - mLooper.dispatchAll(); - assertTrue( - mIkeSessionStateMachine.getCurrentState() - instanceof IkeSessionStateMachine.RekeyIkeLocalCreate); - verifyRetransmissionStarted(); - - // Verify outbound message - IkeMessage rekeyMsg = verifyEncryptAndEncodeAndGetMessage(mSpyCurrentIkeSaRecord); - - IkeHeader ikeHeader = rekeyMsg.ikeHeader; - assertEquals(IkePayload.PAYLOAD_TYPE_SK, ikeHeader.nextPayloadType); - assertEquals(IkeHeader.EXCHANGE_TYPE_CREATE_CHILD_SA, ikeHeader.exchangeType); - assertEquals(mSpyCurrentIkeSaRecord.getLocalRequestMessageId(), ikeHeader.messageId); - assertFalse(ikeHeader.isResponseMsg); - assertTrue(ikeHeader.fromIkeInitiator); - - // Verify SA payload & proposals - IkeSaPayload saPayload = - rekeyMsg.getPayloadForType(IkePayload.PAYLOAD_TYPE_SA, IkeSaPayload.class); - assertFalse(saPayload.isSaResponse); - assertEquals(1, saPayload.proposalList.size()); - - IkeSaPayload.IkeProposal proposal = - (IkeSaPayload.IkeProposal) saPayload.proposalList.get(0); - assertEquals(1, proposal.number); // Must be 1-indexed - assertEquals(IkePayload.PROTOCOL_ID_IKE, proposal.protocolId); - assertEquals(IkePayload.SPI_LEN_IKE, proposal.spiSize); - assertEquals(mIkeSessionStateMachine.mSaProposal, proposal.saProposal); - - // Verify Nonce and KE payloads exist. - assertNotNull( - rekeyMsg.getPayloadForType(IkePayload.PAYLOAD_TYPE_NONCE, IkeNoncePayload.class)); - - IkeKePayload kePayload = - rekeyMsg.getPayloadForType(IkePayload.PAYLOAD_TYPE_KE, IkeKePayload.class); - assertNotNull(kePayload); - assertTrue(kePayload.isOutbound); - } - - @Test - public void testRekeyIkeLocalCreateHandlesResponse() throws Exception { - setupIdleStateMachine(); - - // Send Rekey-Create request - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ, - new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE)); - mLooper.dispatchAll(); - verifyRetransmissionStarted(); - - // Prepare "rekeyed" SA - setupRekeyedIkeSa(mSpyLocalInitIkeSaRecord); - - // Receive Rekey response - ReceivedIkePacket dummyRekeyIkeRespReceivedPacket = makeRekeyIkeResponse(); - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, dummyRekeyIkeRespReceivedPacket); - mLooper.dispatchAll(); - verifyIncrementLocaReqMsgId(); - verifyDecodeEncryptedMessage(mSpyCurrentIkeSaRecord, dummyRekeyIkeRespReceivedPacket); - - // Verify in delete state, and new SA record was saved: - assertTrue( - mIkeSessionStateMachine.getCurrentState() - instanceof IkeSessionStateMachine.RekeyIkeLocalDelete); - verifyRetransmissionStarted(); - assertEquals(mSpyLocalInitIkeSaRecord, mIkeSessionStateMachine.mLocalInitNewIkeSaRecord); - verify(mSpyIkeSocket) - .registerIke( - eq(mSpyLocalInitIkeSaRecord.getLocalSpi()), eq(mIkeSessionStateMachine)); - } - - @Test - public void testRekeyIkeLocalCreateHandleRespWithParsingError() throws Exception { - setupIdleStateMachine(); - - // Send Rekey-Create request - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ, - new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE)); - mLooper.dispatchAll(); - verifyRetransmissionStarted(); - resetMockIkeMessageHelper(); - - // Mock receiving packet with syntax error - ReceivedIkePacket mockInvalidPacket = - makeDummyReceivedIkePacketWithInvalidSyntax( - mSpyCurrentIkeSaRecord, - true /*isResp*/, - IkeHeader.EXCHANGE_TYPE_CREATE_CHILD_SA); - mIkeSessionStateMachine.sendMessage(CMD_RECEIVE_IKE_PACKET, mockInvalidPacket); - mLooper.dispatchAll(); - - // Verify Delete request was sent - List<IkePayload> payloads = verifyOutInfoMsgHeaderAndGetPayloads(false /*isResp*/); - assertEquals(1, payloads.size()); - assertEquals(IkePayload.PAYLOAD_TYPE_DELETE, payloads.get(0).payloadType); - - // Verify IKE Session is closed properly - assertNull(mIkeSessionStateMachine.getCurrentState()); - verify(mMockIkeSessionCallback).onClosedExceptionally(any(InvalidSyntaxException.class)); - } - - @Test - public void testRekeyIkeLocalCreateHandleRespWithNonFatalErrorNotify() throws Exception { - setupIdleStateMachine(); - - // Send Rekey-Create request - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ, - new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE)); - mLooper.dispatchAll(); - - // Mock receiving packet with NO_PROPOSAL_CHOSEN - ReceivedIkePacket resp = - makeResponseWithErrorNotify(new IkeNotifyPayload(ERROR_TYPE_NO_PROPOSAL_CHOSEN)); - mIkeSessionStateMachine.sendMessage(CMD_RECEIVE_IKE_PACKET, resp); - mLooper.dispatchAll(); - - // Verify IKE Session goes back to Idle - assertTrue( - mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle); - - // Move time forward to trigger retry - mLooper.moveTimeForward(IkeSessionStateMachine.RETRY_INTERVAL_MS); - mLooper.dispatchAll(); - - assertTrue( - mIkeSessionStateMachine.getCurrentState() - instanceof IkeSessionStateMachine.RekeyIkeLocalCreate); - } - - @Test - public void testRekeyIkeLocalCreateHandleRespWithFatalErrorNotify() throws Exception { - setupIdleStateMachine(); - - // Send Rekey-Create request - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ, - new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE)); - mLooper.dispatchAll(); - resetMockIkeMessageHelper(); - - // Mock receiving packet with NO_PROPOSAL_CHOSEN - ReceivedIkePacket resp = - makeResponseWithErrorNotify(new IkeNotifyPayload(ERROR_TYPE_INVALID_SYNTAX)); - mIkeSessionStateMachine.sendMessage(CMD_RECEIVE_IKE_PACKET, resp); - mLooper.dispatchAll(); - - // Verify no message was sent because a fatal error notification was received - verifyEncryptAndEncodeNeverCalled(mSpyCurrentIkeSaRecord); - - // Verify IKE Session is closed properly - assertNull(mIkeSessionStateMachine.getCurrentState()); - verify(mMockIkeSessionCallback).onClosedExceptionally(any(InvalidSyntaxException.class)); - } - - @Test - public void testRekeyIkeLocalCreateSaCreationFail() throws Exception { - // Throw error when building new IKE SA - throwExceptionWhenMakeRekeyIkeSa( - new GeneralSecurityException("testRekeyIkeLocalCreateSaCreationFail")); - - setupIdleStateMachine(); - - // Send Rekey-Create request - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ, - new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE)); - mLooper.dispatchAll(); - resetMockIkeMessageHelper(); - - // Receive Rekey response - ReceivedIkePacket dummyRekeyIkeRespReceivedPacket = makeRekeyIkeResponse(); - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, dummyRekeyIkeRespReceivedPacket); - mLooper.dispatchAll(); - - // Verify Delete request was sent - List<IkePayload> payloads = verifyOutInfoMsgHeaderAndGetPayloads(false /*isResp*/); - assertEquals(1, payloads.size()); - assertEquals(IkePayload.PAYLOAD_TYPE_DELETE, payloads.get(0).payloadType); - - // Verify IKE Session is closed properly - assertNull(mIkeSessionStateMachine.getCurrentState()); - verify(mMockIkeSessionCallback).onClosedExceptionally(any(IkeInternalException.class)); - } - - @Test - public void testRekeyIkeLocalCreateHandleReqWithNonFatalError() throws Exception { - setupIdleStateMachine(); - - // Send Rekey-Create request - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ, - new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE)); - mLooper.dispatchAll(); - verifyRetransmissionStarted(); - resetMockIkeMessageHelper(); - - // Build protocol exception - List<Integer> unsupportedPayloads = new LinkedList<>(); - unsupportedPayloads.add(PAYLOAD_TYPE_UNSUPPORTED); - UnsupportedCriticalPayloadException exception = - new UnsupportedCriticalPayloadException(unsupportedPayloads); - - // Mock receiving packet with unsupported critical payload - ReceivedIkePacket mockInvalidPacket = - makeDummyReceivedIkePacketWithDecodingError( - mSpyCurrentIkeSaRecord, - false /*isResp*/, - IkeHeader.EXCHANGE_TYPE_CREATE_CHILD_SA, - exception); - mIkeSessionStateMachine.sendMessage(CMD_RECEIVE_IKE_PACKET, mockInvalidPacket); - mLooper.dispatchAll(); - - // Verify error notification was sent - List<IkePayload> payloads = verifyOutInfoMsgHeaderAndGetPayloads(true /*isResp*/); - assertEquals(1, payloads.size()); - - IkePayload payload = payloads.get(0); - assertEquals(IkePayload.PAYLOAD_TYPE_NOTIFY, payload.payloadType); - assertEquals( - ERROR_TYPE_UNSUPPORTED_CRITICAL_PAYLOAD, ((IkeNotifyPayload) payload).notifyType); - - // Verify IKE Session stays in the same state - assertTrue( - mIkeSessionStateMachine.getCurrentState() - instanceof IkeSessionStateMachine.RekeyIkeLocalCreate); - } - - private void mockCreateAndTransitionToRekeyDeleteLocal() { - // Seed fake rekey data and force transition to RekeyIkeLocalDelete - mIkeSessionStateMachine.mLocalInitNewIkeSaRecord = mSpyLocalInitIkeSaRecord; - mIkeSessionStateMachine.addIkeSaRecord(mSpyLocalInitIkeSaRecord); - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_FORCE_TRANSITION, - mIkeSessionStateMachine.mRekeyIkeLocalDelete); - mLooper.dispatchAll(); - verifyRetransmissionStarted(); - } - - @Test - public void testRekeyIkeLocalDeleteSendsRequest() throws Exception { - setupIdleStateMachine(); - mockCreateAndTransitionToRekeyDeleteLocal(); - - // Verify Rekey-Delete request - assertTrue( - mIkeSessionStateMachine.getCurrentState() - instanceof IkeSessionStateMachine.RekeyIkeLocalDelete); - verifyRetransmissionStarted(); - - // Verify outbound message - IkeMessage delMsg = verifyEncryptAndEncodeAndGetMessage(mSpyCurrentIkeSaRecord); - - IkeHeader ikeHeader = delMsg.ikeHeader; - assertEquals(mSpyCurrentIkeSaRecord.getInitiatorSpi(), ikeHeader.ikeInitiatorSpi); - assertEquals(mSpyCurrentIkeSaRecord.getResponderSpi(), ikeHeader.ikeResponderSpi); - assertEquals(IkePayload.PAYLOAD_TYPE_SK, ikeHeader.nextPayloadType); - assertEquals(IkeHeader.EXCHANGE_TYPE_INFORMATIONAL, ikeHeader.exchangeType); - assertEquals(mSpyCurrentIkeSaRecord.isLocalInit, ikeHeader.fromIkeInitiator); - assertFalse(ikeHeader.isResponseMsg); - - List<IkeDeletePayload> deletePayloadList = - delMsg.getPayloadListForType( - IkePayload.PAYLOAD_TYPE_DELETE, IkeDeletePayload.class); - assertEquals(1, deletePayloadList.size()); - - IkeDeletePayload deletePayload = deletePayloadList.get(0); - assertEquals(IkePayload.PROTOCOL_ID_IKE, deletePayload.protocolId); - assertEquals(0, deletePayload.numSpi); - assertEquals(0, deletePayload.spiSize); - assertArrayEquals(new int[0], deletePayload.spisToDelete); - } - - private void verifyRekeyReplaceSa(IkeSaRecord newSaRecord) { - verify(mSpyCurrentIkeSaRecord).close(); - verify(mSpyIkeSocket).unregisterIke(eq(mSpyCurrentIkeSaRecord.getLocalSpi())); - verify(mSpyIkeSocket, never()).unregisterIke(eq(newSaRecord.getLocalSpi())); - - assertEquals(mIkeSessionStateMachine.mCurrentIkeSaRecord, newSaRecord); - - verify(mMockChildSessionStateMachine).setSkD(newSaRecord.getSkD()); - } - - @Test - public void testRekeyIkeLocalDeleteHandlesResponse() throws Exception { - setupIdleStateMachine(); - mockCreateAndTransitionToRekeyDeleteLocal(); - - // Receive Delete response - ReceivedIkePacket dummyDeleteIkeRespReceivedPacket = - makeDeleteIkeResponse(mSpyCurrentIkeSaRecord); - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, dummyDeleteIkeRespReceivedPacket); - mLooper.dispatchAll(); - verifyIncrementLocaReqMsgId(); - verifyDecodeEncryptedMessage(mSpyCurrentIkeSaRecord, dummyDeleteIkeRespReceivedPacket); - - // Verify final state - Idle, with new SA, and old SA closed. - verifyRekeyReplaceSa(mSpyLocalInitIkeSaRecord); - verify(mMockIkeSessionCallback, never()).onClosed(); - assertTrue( - mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle); - verifyRetransmissionStopped(); - } - - @Test - public void testRekeyIkeLocalDeleteHandlesRespWithParsingError() throws Exception { - setupIdleStateMachine(); - mockCreateAndTransitionToRekeyDeleteLocal(); - resetMockIkeMessageHelper(); - - // Mock receiving packet with syntax error - ReceivedIkePacket mockInvalidPacket = - makeDummyReceivedIkePacketWithInvalidSyntax( - mSpyCurrentIkeSaRecord, - true /*isResp*/, - IkeHeader.EXCHANGE_TYPE_INFORMATIONAL); - mIkeSessionStateMachine.sendMessage(CMD_RECEIVE_IKE_PACKET, mockInvalidPacket); - mLooper.dispatchAll(); - - // Verify no more request out - verifyEncryptAndEncodeNeverCalled(mSpyCurrentIkeSaRecord); - - // Verify final state - Idle, with new SA, and old SA closed. - verifyRekeyReplaceSa(mSpyLocalInitIkeSaRecord); - assertTrue( - mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle); - verifyRetransmissionStopped(); - } - - @Test - public void testRekeyIkeLocalDeleteWithRequestOnNewSa() throws Exception { - setupIdleStateMachine(); - mockCreateAndTransitionToRekeyDeleteLocal(); - - // Receive an empty (DPD) request on the new IKE SA - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, - makeDpdIkeRequest(mSpyLocalInitIkeSaRecord)); - mLooper.dispatchAll(); - - // Verify final state - Idle, with new SA, and old SA closed. - verifyRekeyReplaceSa(mSpyLocalInitIkeSaRecord); - assertTrue( - mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle); - verifyRetransmissionStopped(); - } - - @Test - public void testRekeyIkeLocalDeleteWithRequestFragOnNewSa() throws Exception { - setupIdleStateMachine(); - mockCreateAndTransitionToRekeyDeleteLocal(); - - // Received IKE fragment - byte[] unencryptedData = "testRekeyIkeLocalDeleteWithRequestFragOnNewSa".getBytes(); - int fragNum = 1; - int totalFragments = 2; - IkeSkfPayload skfPayload = - IkeTestUtils.makeDummySkfPayload(unencryptedData, fragNum, totalFragments); - - ReceivedIkePacket packet = - makeDummyReceivedIkeFragmentPacket( - mSpyLocalInitIkeSaRecord, - false /*isResp*/, - IkeHeader.EXCHANGE_TYPE_CREATE_CHILD_SA, - skfPayload, - PAYLOAD_TYPE_SA, - null /* collectedFrags*/); - mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, packet); - mLooper.dispatchAll(); - - // Verify rekey is done. - verifyRekeyReplaceSa(mSpyLocalInitIkeSaRecord); - verifyRetransmissionStopped(); - - // Verify the IkeSaRecord has stored the new fragment. - DecodeResultPartial resultPartial = - mSpyLocalInitIkeSaRecord.getCollectedFragments(false /*isResp*/); - assertEquals(PAYLOAD_TYPE_SA, resultPartial.firstPayloadType); - assertEquals(totalFragments, resultPartial.collectedFragsList.length); - assertArrayEquals(unencryptedData, resultPartial.collectedFragsList[fragNum - 1]); - assertFalse(resultPartial.isAllFragmentsReceived()); - } - - @Test - public void testRekeyIkeRemoteDeleteWithRequestOnNewSa() throws Exception { - setupIdleStateMachine(); - - // Seed fake rekey data and force transition to RekeyIkeRemoteDelete - mIkeSessionStateMachine.mRemoteInitNewIkeSaRecord = mSpyRemoteInitIkeSaRecord; - mIkeSessionStateMachine.addIkeSaRecord(mSpyRemoteInitIkeSaRecord); - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_FORCE_TRANSITION, - mIkeSessionStateMachine.mRekeyIkeRemoteDelete); - mLooper.dispatchAll(); - - // Receive an empty (DPD) request on the new IKE SA - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, - makeDpdIkeRequest(mSpyRemoteInitIkeSaRecord)); - mLooper.dispatchAll(); - - // Verify final state - Idle, with new SA, and old SA closed. - verifyRekeyReplaceSa(mSpyRemoteInitIkeSaRecord); - assertTrue( - mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle); - } - - @Test - public void testRekeyIkeRemoteCreate() throws Exception { - setupIdleStateMachine(); - - setupRekeyedIkeSa(mSpyRemoteInitIkeSaRecord); - - // Receive Rekey request - ReceivedIkePacket dummyRekeyIkeRequestReceivedPacket = makeRekeyIkeRequest(); - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, dummyRekeyIkeRequestReceivedPacket); - mLooper.dispatchAll(); - verifyIncrementRemoteReqMsgId(); - verifyDecodeEncryptedMessage(mSpyCurrentIkeSaRecord, dummyRekeyIkeRequestReceivedPacket); - - // Verify SA created with correct parameters - ArgumentCaptor<SaRecord.IkeSaRecordConfig> recordConfigCaptor = - ArgumentCaptor.forClass(SaRecord.IkeSaRecordConfig.class); - verify(mMockSaRecordHelper) - .makeRekeyedIkeSaRecord(any(), any(), any(), any(), recordConfigCaptor.capture()); - assertEquals(IKE_REKEY_SA_INITIATOR_SPI, recordConfigCaptor.getValue().initSpi.getSpi()); - - // Verify outbound CREATE_CHILD_SA message - IkeMessage rekeyCreateResp = verifyEncryptAndEncodeAndGetMessage(mSpyCurrentIkeSaRecord); - IkeHeader rekeyCreateRespHeader = rekeyCreateResp.ikeHeader; - assertEquals(IkePayload.PAYLOAD_TYPE_SK, rekeyCreateRespHeader.nextPayloadType); - assertEquals(IkeHeader.EXCHANGE_TYPE_CREATE_CHILD_SA, rekeyCreateRespHeader.exchangeType); - assertTrue(rekeyCreateRespHeader.isResponseMsg); - assertTrue(rekeyCreateRespHeader.fromIkeInitiator); - assertNotNull( - rekeyCreateResp.getPayloadForType(IkePayload.PAYLOAD_TYPE_SA, IkeSaPayload.class)); - assertNotNull( - rekeyCreateResp.getPayloadForType(IkePayload.PAYLOAD_TYPE_KE, IkeKePayload.class)); - assertNotNull( - rekeyCreateResp.getPayloadForType( - IkePayload.PAYLOAD_TYPE_NONCE, IkeNoncePayload.class)); - - // Verify SA, StateMachine state - assertEquals(mSpyCurrentIkeSaRecord, mIkeSessionStateMachine.mIkeSaRecordAwaitingRemoteDel); - assertEquals(mSpyRemoteInitIkeSaRecord, mIkeSessionStateMachine.mIkeSaRecordSurviving); - assertTrue( - mIkeSessionStateMachine.getCurrentState() - instanceof IkeSessionStateMachine.RekeyIkeRemoteDelete); - verify(mSpyIkeSocket) - .registerIke( - eq(mSpyRemoteInitIkeSaRecord.getLocalSpi()), eq(mIkeSessionStateMachine)); - } - - @Test - public void testRekeyIkeRemoteCreateHandlesInvalidReq() throws Exception { - setupIdleStateMachine(); - - // Receive Rekey request - ReceivedIkePacket request = makeRekeyIkeRequestWithUnacceptableProposal(); - mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, request); - mLooper.dispatchAll(); - - verifyProcessRekeyReqFailure(ERROR_TYPE_NO_PROPOSAL_CHOSEN); - } - - @Test - public void testRekeyIkeRemoteCreateSaCreationFailure() throws Exception { - // Throw error when building new IKE SA - throwExceptionWhenMakeRekeyIkeSa( - new GeneralSecurityException("testRekeyIkeRemoteCreateSaCreationFailure")); - setupIdleStateMachine(); - - // Receive Rekey request - ReceivedIkePacket request = makeRekeyIkeRequest(); - mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, request); - mLooper.dispatchAll(); - - verifyProcessRekeyReqFailure(ERROR_TYPE_NO_PROPOSAL_CHOSEN); - } - - private void verifyProcessRekeyReqFailure(int expectedErrorCode) { - // Verify IKE Session is back to Idle - assertTrue( - mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle); - - // Verify error notification was sent - List<IkePayload> payloads = verifyOutInfoMsgHeaderAndGetPayloads(true /*isResp*/); - assertEquals(1, payloads.size()); - IkeNotifyPayload notify = (IkeNotifyPayload) payloads.get(0); - assertEquals(expectedErrorCode, notify.notifyType); - } - - @Test - public void testRekeyIkeRemoteDelete() throws Exception { - setupIdleStateMachine(); - - // Seed fake rekey data and force transition to RekeyIkeLocalDelete - mIkeSessionStateMachine.mRemoteInitNewIkeSaRecord = mSpyRemoteInitIkeSaRecord; - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_FORCE_TRANSITION, - mIkeSessionStateMachine.mRekeyIkeRemoteDelete); - mLooper.dispatchAll(); - - // Rekey Delete request - ReceivedIkePacket dummyDeleteIkeRequestReceivedPacket = - makeDeleteIkeRequest(mSpyCurrentIkeSaRecord); - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, dummyDeleteIkeRequestReceivedPacket); - mLooper.dispatchAll(); - verifyIncrementRemoteReqMsgId(); - verifyDecodeEncryptedMessage(mSpyCurrentIkeSaRecord, dummyDeleteIkeRequestReceivedPacket); - - // Verify outbound DELETE_IKE_SA message - IkeMessage rekeyDeleteResp = verifyEncryptAndEncodeAndGetMessage(mSpyCurrentIkeSaRecord); - IkeHeader rekeyDeleteRespHeader = rekeyDeleteResp.ikeHeader; - assertEquals(IkePayload.PAYLOAD_TYPE_SK, rekeyDeleteRespHeader.nextPayloadType); - assertEquals(IkeHeader.EXCHANGE_TYPE_INFORMATIONAL, rekeyDeleteRespHeader.exchangeType); - assertTrue(rekeyDeleteRespHeader.isResponseMsg); - assertTrue(rekeyDeleteRespHeader.fromIkeInitiator); - assertTrue(rekeyDeleteResp.ikePayloadList.isEmpty()); - - // Verify final state - Idle, with new SA, and old SA closed. - verifyRekeyReplaceSa(mSpyRemoteInitIkeSaRecord); - - verify(mMockIkeSessionCallback, never()).onClosed(); - - verifyDecodeEncryptedMessage(mSpyCurrentIkeSaRecord, dummyDeleteIkeRequestReceivedPacket); - assertTrue( - mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle); - } - - @Test - public void testRekeyIkeRemoteDeleteExitAndRenter() throws Exception { - setupIdleStateMachine(); - - // Seed fake rekey data and force transition to RekeyIkeLocalDelete - mIkeSessionStateMachine.mRemoteInitNewIkeSaRecord = mSpyRemoteInitIkeSaRecord; - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_FORCE_TRANSITION, - mIkeSessionStateMachine.mRekeyIkeRemoteDelete); - mLooper.dispatchAll(); - - // Trigger a timeout, and immediately re-enter remote-delete - mLooper.moveTimeForward(IkeSessionStateMachine.REKEY_DELETE_TIMEOUT_MS / 2 + 1); - mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.TIMEOUT_REKEY_REMOTE_DELETE); - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_FORCE_TRANSITION, - mIkeSessionStateMachine.mRekeyIkeRemoteDelete); - mLooper.dispatchAll(); - - // Shift time forward, and assert the previous timeout was NOT fired. - mLooper.moveTimeForward(IkeSessionStateMachine.REKEY_DELETE_TIMEOUT_MS / 2 + 1); - mLooper.dispatchAll(); - - // Verify no request received, or response sent. - verify(mMockIkeMessageHelper, never()).decode(anyInt(), anyObject(), anyObject()); - verifyEncryptAndEncodeNeverCalled(mSpyCurrentIkeSaRecord); - - // Verify final state has not changed - signal was not sent. - assertTrue( - mIkeSessionStateMachine.getCurrentState() - instanceof IkeSessionStateMachine.RekeyIkeRemoteDelete); - } - - @Test - public void testRekeyIkeRemoteDeleteTimedOut() throws Exception { - setupIdleStateMachine(); - - // Seed fake rekey data and force transition to RekeyIkeLocalDelete - mIkeSessionStateMachine.mRemoteInitNewIkeSaRecord = mSpyRemoteInitIkeSaRecord; - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_FORCE_TRANSITION, - mIkeSessionStateMachine.mRekeyIkeRemoteDelete); - mLooper.dispatchAll(); - - mLooper.moveTimeForward(IkeSessionStateMachine.REKEY_DELETE_TIMEOUT_MS); - mLooper.dispatchAll(); - - // Verify no request received, or response sent. - verify(mMockIkeMessageHelper, never()).decode(anyInt(), anyObject(), anyObject()); - verifyEncryptAndEncodeNeverCalled(mSpyCurrentIkeSaRecord); - - // Verify final state - Idle, with new SA, and old SA closed. - verifyRekeyReplaceSa(mSpyRemoteInitIkeSaRecord); - - assertTrue( - mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle); - } - - @Test - public void testSimulRekey() throws Exception { - setupIdleStateMachine(); - - // Prepare "rekeyed" SA - setupRekeyedIkeSa(mSpyLocalInitIkeSaRecord); - when(mSpyLocalInitIkeSaRecord.compareTo(mSpyRemoteInitIkeSaRecord)).thenReturn(1); - - // Send Rekey request on mSpyCurrentIkeSaRecord - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ, - new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE)); - - // Receive Rekey request on mSpyCurrentIkeSaRecord - ReceivedIkePacket dummyRekeyIkeRequestReceivedPacket = makeRekeyIkeRequest(); - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, dummyRekeyIkeRequestReceivedPacket); - mLooper.dispatchAll(); - verifyIncrementRemoteReqMsgId(); - - // Receive Rekey response on mSpyCurrentIkeSaRecord - ReceivedIkePacket dummyRekeyIkeRespReceivedPacket = makeRekeyIkeResponse(); - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, dummyRekeyIkeRespReceivedPacket); - mLooper.dispatchAll(); - verifyIncrementLocaReqMsgId(); - verify(mSpyIkeSocket) - .registerIke( - eq(mSpyLocalInitIkeSaRecord.getLocalSpi()), eq(mIkeSessionStateMachine)); - - // Receive Delete response on mSpyCurrentIkeSaRecord - ReceivedIkePacket dummyDeleteIkeRespReceivedPacket = - makeDeleteIkeResponse(mSpyCurrentIkeSaRecord); - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, dummyDeleteIkeRespReceivedPacket); - mLooper.dispatchAll(); - verifyIncrementLocaReqMsgId(); - - // Verify - verifyDecodeEncryptedMessage(mSpyCurrentIkeSaRecord, dummyRekeyIkeRequestReceivedPacket); - verifyDecodeEncryptedMessage(mSpyCurrentIkeSaRecord, dummyRekeyIkeRespReceivedPacket); - verifyDecodeEncryptedMessage(mSpyCurrentIkeSaRecord, dummyDeleteIkeRespReceivedPacket); - assertTrue( - mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle); - - verifyRekeyReplaceSa(mSpyLocalInitIkeSaRecord); - verify(mMockIkeSessionCallback, never()).onClosed(); - } - - @Test - public void testOpenIkeSession() throws Exception { - assertTrue( - mIkeSessionStateMachine.getCurrentState() - instanceof IkeSessionStateMachine.Initial); - - mIkeSessionStateMachine.openSession(); - mLooper.dispatchAll(); - - assertTrue( - mIkeSessionStateMachine.getCurrentState() - instanceof IkeSessionStateMachine.CreateIkeLocalIkeInit); - } - - @Test - public void testIkeInitSchedulesRekey() throws Exception { - setupFirstIkeSa(); - - // Send IKE INIT request - mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.CMD_LOCAL_REQUEST_CREATE_IKE); - - // Receive IKE INIT response - ReceivedIkePacket dummyReceivedIkePacket = makeIkeInitResponse(); - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, dummyReceivedIkePacket); - - // Mock IKE AUTH and transition to Idle - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_FORCE_TRANSITION, mIkeSessionStateMachine.mIdle); - mLooper.dispatchAll(); - mIkeSessionStateMachine.mSaProposal = buildSaProposal(); - - // Move time forward to trigger rekey - mLooper.moveTimeForward(SA_SOFT_LIFETIME_MS); - mLooper.dispatchAll(); - - assertTrue( - mIkeSessionStateMachine.getCurrentState() - instanceof IkeSessionStateMachine.RekeyIkeLocalCreate); - } - - @Test - public void testRekeyCreateIkeSchedulesRekey() throws Exception { - setupIdleStateMachine(); - - // Send Rekey-Create request - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ, - new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE)); - mLooper.dispatchAll(); - - // Prepare "rekeyed" SA - setupRekeyedIkeSa(mSpyLocalInitIkeSaRecord); - - // Receive Rekey response - ReceivedIkePacket dummyRekeyIkeRespReceivedPacket = makeRekeyIkeResponse(); - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, dummyRekeyIkeRespReceivedPacket); - mLooper.dispatchAll(); - - // Mock rekey delete and transition to Idle - mIkeSessionStateMachine.mCurrentIkeSaRecord = mSpyLocalInitIkeSaRecord; - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_FORCE_TRANSITION, mIkeSessionStateMachine.mIdle); - mLooper.dispatchAll(); - - // Move time forward to trigger rekey - mLooper.moveTimeForward(SA_SOFT_LIFETIME_MS); - mLooper.dispatchAll(); - - assertTrue( - mIkeSessionStateMachine.getCurrentState() - instanceof IkeSessionStateMachine.RekeyIkeLocalCreate); - } - - @Test - public void testBuildEncryptedInformationalMessage() throws Exception { - IkeNotifyPayload payload = new IkeNotifyPayload(ERROR_TYPE_INVALID_SYNTAX, new byte[0]); - - boolean isResp = false; - IkeMessage generated = - mIkeSessionStateMachine.buildEncryptedInformationalMessage( - mSpyCurrentIkeSaRecord, new IkeInformationalPayload[] {payload}, isResp, 0); - - assertEquals(mSpyCurrentIkeSaRecord.getInitiatorSpi(), generated.ikeHeader.ikeInitiatorSpi); - assertEquals(mSpyCurrentIkeSaRecord.getResponderSpi(), generated.ikeHeader.ikeResponderSpi); - assertEquals( - mSpyCurrentIkeSaRecord.getLocalRequestMessageId(), generated.ikeHeader.messageId); - assertEquals(isResp, generated.ikeHeader.isResponseMsg); - assertEquals(IkePayload.PAYLOAD_TYPE_SK, generated.ikeHeader.nextPayloadType); - - List<IkeNotifyPayload> generatedPayloads = - generated.getPayloadListForType( - IkePayload.PAYLOAD_TYPE_NOTIFY, IkeNotifyPayload.class); - assertEquals(1, generatedPayloads.size()); - - IkeNotifyPayload generatedPayload = generatedPayloads.get(0); - assertArrayEquals(new byte[0], generatedPayload.notifyData); - assertEquals(ERROR_TYPE_INVALID_SYNTAX, generatedPayload.notifyType); - } - - private void verifyLastSentRespAllPackets(byte[][] expectedPackets, IkeSaRecord saRecord) { - if (expectedPackets == null) { - assertNull(saRecord.getLastSentRespAllPackets()); - return; - } - - assertEquals(expectedPackets.length, saRecord.getLastSentRespAllPackets().size()); - for (int i = 0; i < expectedPackets.length; i++) { - assertArrayEquals(expectedPackets[i], saRecord.getLastSentRespAllPackets().get(i)); - } - } - - @Test - public void testEncryptedRetransmitterImmediatelySendsRequest() throws Exception { - setupIdleStateMachine(); - byte[][] dummyLastRespBytes = - new byte[][] {"testRetransmitterSendsRequestLastResp".getBytes()}; - mSpyCurrentIkeSaRecord.updateLastSentRespAllPackets(Arrays.asList(dummyLastRespBytes)); - - IkeMessage spyIkeReqMessage = - spy( - new IkeMessage( - new IkeHeader( - mSpyCurrentIkeSaRecord.getInitiatorSpi(), - mSpyCurrentIkeSaRecord.getResponderSpi(), - IkePayload.PAYLOAD_TYPE_SK, - EXCHANGE_TYPE_INFORMATIONAL, - false /*isResp*/, - mSpyCurrentIkeSaRecord.isLocalInit, - mSpyCurrentIkeSaRecord.getLocalRequestMessageId()), - new LinkedList<>())); - - // Use something unique as a sentinel value - byte[][] dummyReqBytesList = - new byte[][] { - "testRetransmitterSendsReqFrag1".getBytes(), - "testRetransmitterSendsReqFrag2".getBytes() - }; - - doReturn(dummyReqBytesList) - .when(spyIkeReqMessage) - .encryptAndEncode(any(), any(), eq(mSpyCurrentIkeSaRecord), anyBoolean(), anyInt()); - - IkeSessionStateMachine.EncryptedRetransmitter retransmitter = - mIkeSessionStateMachine.new EncryptedRetransmitter(spyIkeReqMessage); - - // Verify message is sent out, and that request does not change cached retransmit-response - // mLastSentIkeResp. - verify(mSpyIkeSocket).sendIkePacket(eq(dummyReqBytesList[0]), eq(REMOTE_ADDRESS)); - verify(mSpyIkeSocket).sendIkePacket(eq(dummyReqBytesList[1]), eq(REMOTE_ADDRESS)); - verifyLastSentRespAllPackets(dummyLastRespBytes, mSpyCurrentIkeSaRecord); - } - - // TODO: b/141275871 Test retransmisstions are fired for correct times within certain time. - - @Test - public void testCacheLastRequestAndResponse() throws Exception { - setupIdleStateMachine(); - mSpyCurrentIkeSaRecord.updateLastReceivedReqFirstPacket(null /*reqPacket*/); - mSpyCurrentIkeSaRecord.updateLastSentRespAllPackets(null /*respPacketList*/); - - byte[] dummyIkeReqFirstPacket = "testLastSentRequest".getBytes(); - byte[][] dummyIkeResp = - new byte[][] { - "testLastSentRespFrag1".getBytes(), "testLastSentRespFrag2".getBytes() - }; - - when(mMockIkeMessageHelper.encryptAndEncode( - any(), - any(), - eq(mSpyCurrentIkeSaRecord), - any(IkeMessage.class), - anyBoolean(), - anyInt())) - .thenReturn(dummyIkeResp); - - // Receive a DPD request, expect to send dummyIkeResp - ReceivedIkePacket dummyDpdRequest = - makeDpdIkeRequest( - mSpyCurrentIkeSaRecord.getRemoteRequestMessageId(), dummyIkeReqFirstPacket); - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, dummyDpdRequest); - mLooper.dispatchAll(); - - verify(mSpyIkeSocket).sendIkePacket(eq(dummyIkeResp[0]), eq(REMOTE_ADDRESS)); - verify(mSpyIkeSocket).sendIkePacket(eq(dummyIkeResp[1]), eq(REMOTE_ADDRESS)); - - verifyLastSentRespAllPackets(dummyIkeResp, mSpyCurrentIkeSaRecord); - assertTrue(mSpyCurrentIkeSaRecord.isRetransmittedRequest(dummyIkeReqFirstPacket)); - - assertTrue( - mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle); - } - - @Test - public void testReplyRetransmittedRequest() throws Exception { - setupIdleStateMachine(); - - // Mock last sent request and response - byte[] dummyIkeReqFirstPacket = "testRcvRetransmittedRequestReq".getBytes(); - byte[][] dummyIkeResp = new byte[][] {"testRcvRetransmittedRequestResp".getBytes()}; - - mSpyCurrentIkeSaRecord.updateLastReceivedReqFirstPacket(dummyIkeReqFirstPacket); - mSpyCurrentIkeSaRecord.updateLastSentRespAllPackets(Arrays.asList(dummyIkeResp)); - mSpyCurrentIkeSaRecord.incrementRemoteRequestMessageId(); - - // Build request with last validated message ID - ReceivedIkePacket request = - makeDpdIkeRequest( - mSpyCurrentIkeSaRecord.getRemoteRequestMessageId() - 1, - dummyIkeReqFirstPacket); - - mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, request); - - mLooper.dispatchAll(); - - verifyLastSentRespAllPackets(dummyIkeResp, mSpyCurrentIkeSaRecord); - verify(mSpyIkeSocket).sendIkePacket(eq(dummyIkeResp[0]), eq(REMOTE_ADDRESS)); - - assertTrue( - mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle); - } - - @Test - public void testDiscardFakeRetransmittedRequest() throws Exception { - setupIdleStateMachine(); - - // Mock last sent request and response - byte[] dummyIkeReqFirstPacket = "testDiscardFakeRetransmittedRequestReq".getBytes(); - byte[][] dummyIkeResp = new byte[][] {"testDiscardFakeRetransmittedRequestResp".getBytes()}; - mSpyCurrentIkeSaRecord.updateLastReceivedReqFirstPacket(dummyIkeReqFirstPacket); - mSpyCurrentIkeSaRecord.updateLastSentRespAllPackets(Arrays.asList(dummyIkeResp)); - mSpyCurrentIkeSaRecord.incrementRemoteRequestMessageId(); - - // Build request with last validated message ID but different bytes - ReceivedIkePacket request = - makeDpdIkeRequest( - mSpyCurrentIkeSaRecord.getRemoteRequestMessageId() - 1, new byte[0]); - - mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, request); - - mLooper.dispatchAll(); - - verifyLastSentRespAllPackets(dummyIkeResp, mSpyCurrentIkeSaRecord); - verify(mSpyIkeSocket, never()).sendIkePacket(any(), any()); - - assertTrue( - mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle); - } - - @Test - public void testDiscardRetransmittedResponse() throws Exception { - mockIkeInitAndTransitionToIkeAuth(mIkeSessionStateMachine.mCreateIkeLocalIkeAuth); - verifyRetransmissionStarted(); - - // Build and send fake response with last validated message ID to IKE state machine - ReceivedIkePacket resp = - makeDummyEncryptedReceivedIkePacketWithPayloadList( - mSpyCurrentIkeSaRecord, - IkeHeader.EXCHANGE_TYPE_IKE_SA_INIT, - true /*isResp*/, - mSpyCurrentIkeSaRecord.getLocalRequestMessageId() - 1, - new LinkedList<>(), - new byte[0]); - - mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, resp); - mLooper.dispatchAll(); - - // Verify current state does not change - verifyRetransmissionStarted(); - assertTrue( - mIkeSessionStateMachine.getCurrentState() - instanceof IkeSessionStateMachine.CreateIkeLocalIkeAuth); - } - - @Test - public void testDeleteIkeLocalDeleteRequest() throws Exception { - setupIdleStateMachine(); - - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ, - new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_DELETE_IKE)); - mLooper.dispatchAll(); - verifyRetransmissionStarted(); - - // Verify outbound message - IkeMessage delMsg = verifyEncryptAndEncodeAndGetMessage(mSpyCurrentIkeSaRecord); - - IkeHeader ikeHeader = delMsg.ikeHeader; - assertEquals(IkePayload.PAYLOAD_TYPE_SK, ikeHeader.nextPayloadType); - assertEquals(IkeHeader.EXCHANGE_TYPE_INFORMATIONAL, ikeHeader.exchangeType); - assertFalse(ikeHeader.isResponseMsg); - assertTrue(ikeHeader.fromIkeInitiator); - - List<IkeDeletePayload> deletePayloadList = - delMsg.getPayloadListForType( - IkePayload.PAYLOAD_TYPE_DELETE, IkeDeletePayload.class); - assertEquals(1, deletePayloadList.size()); - - IkeDeletePayload deletePayload = deletePayloadList.get(0); - assertEquals(IkePayload.PROTOCOL_ID_IKE, deletePayload.protocolId); - assertEquals(0, deletePayload.numSpi); - assertEquals(0, deletePayload.spiSize); - assertArrayEquals(new int[0], deletePayload.spisToDelete); - } - - @Test - public void testDeleteIkeLocalDeleteResponse() throws Exception { - setupIdleStateMachine(); - - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ, - new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_DELETE_IKE)); - mLooper.dispatchAll(); - verifyRetransmissionStarted(); - - ReceivedIkePacket received = makeDeleteIkeResponse(mSpyCurrentIkeSaRecord); - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, received); - mLooper.dispatchAll(); - verifyIncrementLocaReqMsgId(); - - verifyNotifyUserCloseSession(); - - // Verify state machine quit properly - assertNull(mIkeSessionStateMachine.getCurrentState()); - } - - @Test - public void testDeleteIkeLocalDeleteResponseWithParsingError() throws Exception { - setupIdleStateMachine(); - - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ, - new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_DELETE_IKE)); - mLooper.dispatchAll(); - verifyRetransmissionStarted(); - resetMockIkeMessageHelper(); - - // Mock receiving response with syntax error - ReceivedIkePacket mockInvalidPacket = - makeDummyReceivedIkePacketWithInvalidSyntax( - mSpyCurrentIkeSaRecord, - true /*isResp*/, - IkeHeader.EXCHANGE_TYPE_INFORMATIONAL); - mIkeSessionStateMachine.sendMessage(CMD_RECEIVE_IKE_PACKET, mockInvalidPacket); - mLooper.dispatchAll(); - - // Verify no more request out - verifyEncryptAndEncodeNeverCalled(mSpyCurrentIkeSaRecord); - - // Verify state machine quit properly - verify(mMockIkeSessionCallback).onClosedExceptionally(any(InvalidSyntaxException.class)); - assertNull(mIkeSessionStateMachine.getCurrentState()); - } - - @Test - public void testDeleteIkeLocalDeleteHandlesInvalidResp() throws Exception { - setupIdleStateMachine(); - - // Send delete request - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ, - new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_DELETE_IKE)); - mLooper.dispatchAll(); - - // Receive response with wrong exchange type - ReceivedIkePacket resp = - makeDummyReceivedIkePacketWithInvalidSyntax( - mSpyCurrentIkeSaRecord, - true /*isResp*/, - IkeHeader.EXCHANGE_TYPE_CREATE_CHILD_SA); - mIkeSessionStateMachine.sendMessage(CMD_RECEIVE_IKE_PACKET, resp); - mLooper.dispatchAll(); - - // Verify state machine quit properly - verify(mMockIkeSessionCallback).onClosedExceptionally(any(InvalidSyntaxException.class)); - assertNull(mIkeSessionStateMachine.getCurrentState()); - } - - @Test - public void testDeleteIkeLocalDeleteReceivedNonDeleteRequest() throws Exception { - setupIdleStateMachine(); - - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ, - new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_DELETE_IKE)); - mLooper.dispatchAll(); - verifyRetransmissionStarted(); - - // Verify delete sent out. - verifyEncryptAndEncodeAndGetMessage(mSpyCurrentIkeSaRecord); - - resetMockIkeMessageHelper(); // Discard value. - - ReceivedIkePacket received = makeRekeyIkeRequest(); - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, received); - - mLooper.dispatchAll(); - verifyRetransmissionStarted(); - verifyIncrementRemoteReqMsgId(); - - // Verify outbound response - IkeMessage resp = verifyEncryptAndEncodeAndGetMessage(mSpyCurrentIkeSaRecord); - - IkeHeader ikeHeader = resp.ikeHeader; - assertEquals(IkePayload.PAYLOAD_TYPE_SK, ikeHeader.nextPayloadType); - assertEquals(IkeHeader.EXCHANGE_TYPE_INFORMATIONAL, ikeHeader.exchangeType); - assertTrue(ikeHeader.isResponseMsg); - assertEquals(mSpyCurrentIkeSaRecord.isLocalInit, ikeHeader.fromIkeInitiator); - - List<IkeNotifyPayload> notificationPayloadList = - resp.getPayloadListForType(IkePayload.PAYLOAD_TYPE_NOTIFY, IkeNotifyPayload.class); - assertEquals(1, notificationPayloadList.size()); - - IkeNotifyPayload notifyPayload = notificationPayloadList.get(0); - assertEquals(IkeProtocolException.ERROR_TYPE_TEMPORARY_FAILURE, notifyPayload.notifyType); - } - - @Test - public void testDeleteIkeRemoteDelete() throws Exception { - setupIdleStateMachine(); - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, - makeDeleteIkeRequest(mSpyCurrentIkeSaRecord)); - - mLooper.dispatchAll(); - verifyIncrementRemoteReqMsgId(); - - // Verify outbound message - IkeMessage delMsg = verifyEncryptAndEncodeAndGetMessage(mSpyCurrentIkeSaRecord); - - IkeHeader ikeHeader = delMsg.ikeHeader; - assertEquals(IkePayload.PAYLOAD_TYPE_SK, ikeHeader.nextPayloadType); - assertEquals(IkeHeader.EXCHANGE_TYPE_INFORMATIONAL, ikeHeader.exchangeType); - assertTrue(ikeHeader.isResponseMsg); - assertEquals(mSpyCurrentIkeSaRecord.isLocalInit, ikeHeader.fromIkeInitiator); - - assertTrue(delMsg.ikePayloadList.isEmpty()); - - verifyNotifyUserCloseSession(); - - // Verify state machine quit properly - assertNull(mIkeSessionStateMachine.getCurrentState()); - } - - @Test - public void testReceiveDpd() throws Exception { - setupIdleStateMachine(); - - // Receive a DPD request, expect to stay in IDLE state - ReceivedIkePacket dummyDpdRequest = makeDpdIkeRequest(mSpyCurrentIkeSaRecord); - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, dummyDpdRequest); - mLooper.dispatchAll(); - assertTrue( - mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle); - - verifyDecodeEncryptedMessage(mSpyCurrentIkeSaRecord, dummyDpdRequest); - - // Verify outbound response - IkeMessage resp = verifyEncryptAndEncodeAndGetMessage(mSpyCurrentIkeSaRecord); - IkeHeader ikeHeader = resp.ikeHeader; - assertEquals(IkePayload.PAYLOAD_TYPE_SK, ikeHeader.nextPayloadType); - assertEquals(IkeHeader.EXCHANGE_TYPE_INFORMATIONAL, ikeHeader.exchangeType); - assertTrue(ikeHeader.isResponseMsg); - assertEquals(mSpyCurrentIkeSaRecord.isLocalInit, ikeHeader.fromIkeInitiator); - assertTrue(resp.ikePayloadList.isEmpty()); - } - - @Test - public void testReceiveDpdNonIdle() throws Exception { - setupIdleStateMachine(); - - // Move to a non-idle state. Use RekeyIkeRemoteDelete, as it doesn't send out any requests. - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_FORCE_TRANSITION, - mIkeSessionStateMachine.mRekeyIkeRemoteDelete); - mLooper.dispatchAll(); - - // In a rekey state, receiving (and handling) a DPD should not result in a change of states - ReceivedIkePacket dummyDpdRequest = makeDpdIkeRequest(mSpyCurrentIkeSaRecord); - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, dummyDpdRequest); - mLooper.dispatchAll(); - assertTrue( - mIkeSessionStateMachine.getCurrentState() - instanceof IkeSessionStateMachine.RekeyIkeRemoteDelete); - - verifyDecodeEncryptedMessage(mSpyCurrentIkeSaRecord, dummyDpdRequest); - - // Verify outbound response - IkeMessage resp = verifyEncryptAndEncodeAndGetMessage(mSpyCurrentIkeSaRecord); - IkeHeader ikeHeader = resp.ikeHeader; - assertEquals(IkePayload.PAYLOAD_TYPE_SK, ikeHeader.nextPayloadType); - assertEquals(IkeHeader.EXCHANGE_TYPE_INFORMATIONAL, ikeHeader.exchangeType); - assertTrue(ikeHeader.isResponseMsg); - assertEquals(mSpyCurrentIkeSaRecord.isLocalInit, ikeHeader.fromIkeInitiator); - assertTrue(resp.ikePayloadList.isEmpty()); - } - - @Test - public void testIdleTriggersNewRequests() throws Exception { - setupIdleStateMachine(); - - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ, - new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE)); - mLooper.dispatchAll(); - - // Verify that the command is executed, and the state machine transitions to the right state - assertTrue( - mIkeSessionStateMachine.getCurrentState() - instanceof IkeSessionStateMachine.RekeyIkeLocalCreate); - verifyRetransmissionStarted(); - } - - @Test - public void testNonIdleStateDoesNotTriggerNewRequests() throws Exception { - setupIdleStateMachine(); - - // Force ourselves into a non-idle state - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_FORCE_TRANSITION, mIkeSessionStateMachine.mReceiving); - mLooper.dispatchAll(); - verifyEncryptAndEncodeNeverCalled(); - - // Queue a local request, and expect that it is not run (yet) - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE, - new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE)); - mLooper.dispatchAll(); - - // Verify that the state machine is still in the Receiving state - verifyEncryptAndEncodeNeverCalled(); - assertTrue( - mIkeSessionStateMachine.getCurrentState() - instanceof IkeSessionStateMachine.Receiving); - - // Go back to Idle, and expect to immediately transition to RekeyIkeLocalCreate from the - // queued request - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_FORCE_TRANSITION, mIkeSessionStateMachine.mIdle); - mLooper.dispatchAll(); - assertTrue( - mIkeSessionStateMachine.getCurrentState() - instanceof IkeSessionStateMachine.RekeyIkeLocalCreate); - verifyEncryptAndEncodeAndGetMessage(mSpyCurrentIkeSaRecord); - } - - @Test - public void testOpenChildSessionValidatesArgs() throws Exception { - setupIdleStateMachine(); - - // Expect failure - no callbacks provided - try { - mIkeSessionStateMachine.openChildSession(mChildSessionOptions, null); - } catch (IllegalArgumentException expected) { - } - - // Expect failure - callbacks already registered - try { - mIkeSessionStateMachine.openChildSession( - mChildSessionOptions, mMockChildSessionCallback); - } catch (IllegalArgumentException expected) { - } - } - - @Test - public void testOpenChildSession() throws Exception { - setupIdleStateMachine(); - - ChildSessionCallback cb = mock(ChildSessionCallback.class); - mIkeSessionStateMachine.openChildSession(mChildSessionOptions, cb); - - // Test that inserting the same cb returns an error, even before the state - // machine has a chance to process it. - try { - mIkeSessionStateMachine.openChildSession(mChildSessionOptions, cb); - } catch (IllegalArgumentException expected) { - } - - verify(mMockChildSessionFactoryHelper) - .makeChildSessionStateMachine( - eq(mLooper.getLooper()), - eq(mContext), - eq(mChildSessionOptions), - eq(mSpyUserCbExecutor), - eq(cb), - any()); - - // Verify state in IkeSessionStateMachine - mLooper.dispatchAll(); - assertTrue( - mIkeSessionStateMachine.getCurrentState() - instanceof IkeSessionStateMachine.ChildProcedureOngoing); - - synchronized (mIkeSessionStateMachine.mChildCbToSessions) { - assertTrue(mIkeSessionStateMachine.mChildCbToSessions.containsKey(cb)); - } - } - - @Test - public void testCloseChildSessionValidatesArgs() throws Exception { - setupIdleStateMachine(); - - // Expect failure - callbacks not registered - try { - mIkeSessionStateMachine.closeChildSession(mock(ChildSessionCallback.class)); - } catch (IllegalArgumentException expected) { - } - } - - @Test - public void testCloseChildSession() throws Exception { - setupIdleStateMachine(); - - mIkeSessionStateMachine.closeChildSession(mMockChildSessionCallback); - mLooper.dispatchAll(); - - assertTrue( - mIkeSessionStateMachine.getCurrentState() - instanceof IkeSessionStateMachine.ChildProcedureOngoing); - } - - @Test - public void testCloseImmediatelyAfterOpenChildSession() throws Exception { - setupIdleStateMachine(); - - ChildSessionCallback cb = mock(ChildSessionCallback.class); - mIkeSessionStateMachine.openChildSession(mChildSessionOptions, cb); - - // Verify that closing the session immediately still picks up the child callback - // even before the looper has a chance to run. - mIkeSessionStateMachine.closeChildSession(mMockChildSessionCallback); - } - - @Test - public void testOnChildSessionClosed() throws Exception { - setupIdleStateMachine(); - - mDummyChildSmCallback.onChildSessionClosed(mMockChildSessionCallback); - - synchronized (mIkeSessionStateMachine.mChildCbToSessions) { - assertFalse( - mIkeSessionStateMachine.mChildCbToSessions.containsKey( - mMockChildSessionCallback)); - } - } - - @Test - public void testHandleUnexpectedExceptionInEnterState() throws Exception { - Log spyIkeLog = TestUtils.makeSpyLogDoLogErrorForWtf(TAG); - IkeManager.setIkeLog(spyIkeLog); - - IkeSessionOptions mockSessionOptions = mock(IkeSessionOptions.class); - when(mockSessionOptions.getSaProposals()).thenThrow(mock(RuntimeException.class)); - - IkeSessionStateMachine ikeSession = - new IkeSessionStateMachine( - mLooper.getLooper(), - mContext, - mIpSecManager, - mockSessionOptions, - mChildSessionOptions, - mSpyUserCbExecutor, - mMockIkeSessionCallback, - mMockChildSessionCallback, - mMockEapAuthenticatorFactory); - // Send IKE INIT request - mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.CMD_LOCAL_REQUEST_CREATE_IKE); - mLooper.dispatchAll(); - - assertNull(ikeSession.getCurrentState()); - verify(mSpyUserCbExecutor).execute(any(Runnable.class)); - verify(mMockIkeSessionCallback).onClosedExceptionally(any(IkeInternalException.class)); - verify(spyIkeLog).wtf(anyString(), anyString(), any(RuntimeException.class)); - } - - @Test - public void testHandleUnexpectedExceptionInProcessStateMsg() throws Exception { - Log spyIkeLog = TestUtils.makeSpyLogDoLogErrorForWtf(TAG); - IkeManager.setIkeLog(spyIkeLog); - - setupIdleStateMachine(); - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, null /*receivedIkePacket*/); - mLooper.dispatchAll(); - - assertNull(mIkeSessionStateMachine.getCurrentState()); - verify(mSpyUserCbExecutor).execute(any(Runnable.class)); - verify(mMockIkeSessionCallback).onClosedExceptionally(any(IkeInternalException.class)); - verify(spyIkeLog).wtf(anyString(), anyString(), any(RuntimeException.class)); - } - - @Test - public void testCreateIkeLocalIkeInitRcvErrorNotify() throws Exception { - // Send IKE INIT request - mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.CMD_LOCAL_REQUEST_CREATE_IKE); - mLooper.dispatchAll(); - verifyRetransmissionStarted(); - - // Receive IKE INIT response with erro notification. - List<IkePayload> payloads = new LinkedList<>(); - payloads.add(new IkeNotifyPayload(IkeProtocolException.ERROR_TYPE_NO_PROPOSAL_CHOSEN)); - ReceivedIkePacket resp = - makeDummyUnencryptedReceivedIkePacket( - 1L /*initiator SPI*/, - 2L /*respodner SPI*/, - IkeHeader.EXCHANGE_TYPE_IKE_SA_INIT, - true /*isResp*/, - false /*fromIkeInit*/, - payloads); - - mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, resp); - mLooper.dispatchAll(); - - // Fires user error callbacks - verify(mMockIkeSessionCallback) - .onClosedExceptionally( - argThat(err -> err instanceof NoValidProposalChosenException)); - // Verify state machine quit properly - assertNull(mIkeSessionStateMachine.getCurrentState()); - } - - private void mockSendRekeyChildReq() throws Exception { - setupIdleStateMachine(); - - ChildLocalRequest childLocalRequest = - new ChildLocalRequest( - IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_CHILD, - mMockChildSessionCallback, - null /*childOptions*/); - - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ, childLocalRequest); - mLooper.dispatchAll(); - - assertTrue( - mIkeSessionStateMachine.getCurrentState() - instanceof IkeSessionStateMachine.ChildProcedureOngoing); - verify(mMockChildSessionStateMachine).rekeyChildSession(); - - // Mocking sending request - mDummyChildSmCallback.onOutboundPayloadsReady( - IkeHeader.EXCHANGE_TYPE_CREATE_CHILD_SA, - false /*isResp*/, - new LinkedList<>(), - mMockChildSessionStateMachine); - mLooper.dispatchAll(); - } - - private void mockRcvTempFail() throws Exception { - ReceivedIkePacket resp = - makeResponseWithErrorNotify(new IkeNotifyPayload(ERROR_TYPE_TEMPORARY_FAILURE)); - - mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, resp); - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_FORCE_TRANSITION, mIkeSessionStateMachine.mIdle); - mLooper.dispatchAll(); - } - - @Test - public void testTempFailureHandlerScheduleRetry() throws Exception { - mockSendRekeyChildReq(); - - // Mock sending TEMPORARY_FAILURE response - mockRcvTempFail(); - - // Move time forward to trigger retry - mLooper.moveTimeForward(IkeSessionStateMachine.RETRY_INTERVAL_MS); - mLooper.dispatchAll(); - - // Verify that rekey is triggered again - assertTrue( - mIkeSessionStateMachine.getCurrentState() - instanceof IkeSessionStateMachine.ChildProcedureOngoing); - verify(mMockChildSessionStateMachine, times(2)).rekeyChildSession(); - } - - @Test - public void testTempFailureHandlerTimeout() throws Exception { - long currentTime = 0; - int retryCnt = 0; - - mockSendRekeyChildReq(); - - while (currentTime + RETRY_INTERVAL_MS < TEMP_FAILURE_RETRY_TIMEOUT_MS) { - mockRcvTempFail(); - - mLooper.moveTimeForward(RETRY_INTERVAL_MS); - currentTime += RETRY_INTERVAL_MS; - mLooper.dispatchAll(); - - retryCnt++; - verify(mMockChildSessionStateMachine, times(1 + retryCnt)).rekeyChildSession(); - } - - mLooper.moveTimeForward(RETRY_INTERVAL_MS); - mLooper.dispatchAll(); - - assertNull(mIkeSessionStateMachine.getCurrentState()); - verify(mMockIkeSessionCallback).onClosedExceptionally(any(IkeInternalException.class)); - } - - @Test - public void testTempFailureHandlerCancelTimer() throws Exception { - mockSendRekeyChildReq(); - - // Mock sending TEMPORARY_FAILURE response - mockRcvTempFail(); - - // Move time forward to trigger retry - mLooper.moveTimeForward(IkeSessionStateMachine.RETRY_INTERVAL_MS); - mLooper.dispatchAll(); - verify(mMockChildSessionStateMachine, times(2)).rekeyChildSession(); - - // Mock sending a valid response - ReceivedIkePacket resp = - makeDummyEncryptedReceivedIkePacketWithPayloadList( - mSpyCurrentIkeSaRecord, - EXCHANGE_TYPE_CREATE_CHILD_SA, - true /*isResp*/, - new LinkedList<>()); - mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, resp); - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_FORCE_TRANSITION, mIkeSessionStateMachine.mIdle); - mLooper.dispatchAll(); - - // Move time forward - mLooper.moveTimeForward(IkeSessionStateMachine.TEMP_FAILURE_RETRY_TIMEOUT_MS); - mLooper.dispatchAll(); - - // Validate IKE Session is not closed - assertTrue( - mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle); - // Validate no more retry - verify(mMockChildSessionStateMachine, times(2)).rekeyChildSession(); - } - - @Test - public void testIdleReceiveRequestWithFatalError() throws Exception { - setupIdleStateMachine(); - - // Mock receiving packet with syntax error - ReceivedIkePacket mockInvalidPacket = - makeDummyReceivedIkePacketWithInvalidSyntax( - mSpyCurrentIkeSaRecord, - false /*isResp*/, - IkeHeader.EXCHANGE_TYPE_CREATE_CHILD_SA); - mIkeSessionStateMachine.sendMessage(CMD_RECEIVE_IKE_PACKET, mockInvalidPacket); - mLooper.dispatchAll(); - - // Verify Delete request was sent - List<IkePayload> payloads = verifyOutInfoMsgHeaderAndGetPayloads(true /*isResp*/); - assertEquals(1, payloads.size()); - - IkePayload payload = payloads.get(0); - assertEquals(IkePayload.PAYLOAD_TYPE_NOTIFY, payload.payloadType); - assertEquals(ERROR_TYPE_INVALID_SYNTAX, ((IkeNotifyPayload) payload).notifyType); - - // Verify IKE Session is closed properly - assertNull(mIkeSessionStateMachine.getCurrentState()); - verify(mMockIkeSessionCallback).onClosedExceptionally(any(InvalidSyntaxException.class)); - } - - @Test - public void testHandlesInvalidRequest() throws Exception { - setupIdleStateMachine(); - - mIkeSessionStateMachine.sendMessage( - IkeSessionStateMachine.CMD_FORCE_TRANSITION, - mIkeSessionStateMachine.mChildProcedureOngoing); - - // Receive an IKE AUTH request - ReceivedIkePacket request = - makeDummyEncryptedReceivedIkePacketWithPayloadList( - mSpyCurrentIkeSaRecord, - IkeHeader.EXCHANGE_TYPE_IKE_AUTH, - false /*isResp*/, - new LinkedList<IkePayload>()); - mIkeSessionStateMachine.sendMessage(IkeSessionStateMachine.CMD_RECEIVE_IKE_PACKET, request); - mLooper.dispatchAll(); - - // Verify error notification was sent - List<IkePayload> ikePayloadList = verifyOutInfoMsgHeaderAndGetPayloads(true /*isResp*/); - assertEquals(1, ikePayloadList.size()); - assertEquals( - ERROR_TYPE_INVALID_SYNTAX, ((IkeNotifyPayload) ikePayloadList.get(0)).notifyType); - - // Verify IKE Session has quit - assertNull(mIkeSessionStateMachine.getCurrentState()); - verify(mMockIkeSessionCallback).onClosedExceptionally(any(InvalidSyntaxException.class)); - } - - @Test - public void testIdleHandlesUnprotectedPacket() throws Exception { - setupIdleStateMachine(); - - ReceivedIkePacket req = - makeDummyReceivedIkePacketWithUnprotectedError( - mSpyCurrentIkeSaRecord, - false /*isResp*/, - EXCHANGE_TYPE_INFORMATIONAL, - mock(IkeException.class)); - - mLooper.dispatchAll(); - assertTrue( - mIkeSessionStateMachine.getCurrentState() instanceof IkeSessionStateMachine.Idle); - } -} |