1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.internal.net.ipsec.test.ike; 18 19 import static android.net.ipsec.test.ike.SaProposal.DH_GROUP_2048_BIT_MODP; 20 import static android.net.ipsec.test.ike.exceptions.IkeProtocolException.ERROR_TYPE_INTERNAL_ADDRESS_FAILURE; 21 import static android.net.ipsec.test.ike.exceptions.IkeProtocolException.ERROR_TYPE_INVALID_KE_PAYLOAD; 22 import static android.net.ipsec.test.ike.exceptions.IkeProtocolException.ERROR_TYPE_INVALID_SYNTAX; 23 import static android.net.ipsec.test.ike.exceptions.IkeProtocolException.ERROR_TYPE_NO_ADDITIONAL_SAS; 24 import static android.net.ipsec.test.ike.exceptions.IkeProtocolException.ERROR_TYPE_NO_PROPOSAL_CHOSEN; 25 import static android.net.ipsec.test.ike.exceptions.IkeProtocolException.ERROR_TYPE_TEMPORARY_FAILURE; 26 import static android.system.OsConstants.AF_INET; 27 28 import static com.android.internal.net.TestUtils.createMockRandomFactory; 29 import static com.android.internal.net.ipsec.test.ike.AbstractSessionStateMachine.CMD_LOCAL_REQUEST_CREATE_CHILD; 30 import static com.android.internal.net.ipsec.test.ike.AbstractSessionStateMachine.RETRY_INTERVAL_MS; 31 import static com.android.internal.net.ipsec.test.ike.ChildSessionStateMachine.CMD_FORCE_TRANSITION; 32 import static com.android.internal.net.ipsec.test.ike.IkeSessionStateMachine.REKEY_DELETE_TIMEOUT_MS; 33 import static com.android.internal.net.ipsec.test.ike.message.IkeHeader.EXCHANGE_TYPE_CREATE_CHILD_SA; 34 import static com.android.internal.net.ipsec.test.ike.message.IkeHeader.EXCHANGE_TYPE_INFORMATIONAL; 35 import static com.android.internal.net.ipsec.test.ike.message.IkeMessage.IKE_EXCHANGE_SUBTYPE_DELETE_CHILD; 36 import static com.android.internal.net.ipsec.test.ike.message.IkeMessage.IKE_EXCHANGE_SUBTYPE_REKEY_CHILD; 37 import static com.android.internal.net.ipsec.test.ike.message.IkeNotifyPayload.NOTIFY_TYPE_REKEY_SA; 38 import static com.android.internal.net.ipsec.test.ike.message.IkePayload.PAYLOAD_TYPE_CP; 39 import static com.android.internal.net.ipsec.test.ike.message.IkePayload.PAYLOAD_TYPE_DELETE; 40 import static com.android.internal.net.ipsec.test.ike.message.IkePayload.PAYLOAD_TYPE_KE; 41 import static com.android.internal.net.ipsec.test.ike.message.IkePayload.PAYLOAD_TYPE_NONCE; 42 import static com.android.internal.net.ipsec.test.ike.message.IkePayload.PAYLOAD_TYPE_NOTIFY; 43 import static com.android.internal.net.ipsec.test.ike.message.IkePayload.PAYLOAD_TYPE_SA; 44 import static com.android.internal.net.ipsec.test.ike.message.IkePayload.PAYLOAD_TYPE_TS_INITIATOR; 45 import static com.android.internal.net.ipsec.test.ike.message.IkePayload.PAYLOAD_TYPE_TS_RESPONDER; 46 import static com.android.internal.net.ipsec.test.ike.message.IkePayload.PROTOCOL_ID_ESP; 47 48 import static org.junit.Assert.assertArrayEquals; 49 import static org.junit.Assert.assertEquals; 50 import static org.junit.Assert.assertFalse; 51 import static org.junit.Assert.assertNotNull; 52 import static org.junit.Assert.assertNull; 53 import static org.junit.Assert.assertTrue; 54 import static org.junit.Assert.fail; 55 import static org.mockito.ArgumentMatchers.any; 56 import static org.mockito.ArgumentMatchers.anyBoolean; 57 import static org.mockito.ArgumentMatchers.anyInt; 58 import static org.mockito.ArgumentMatchers.anyString; 59 import static org.mockito.ArgumentMatchers.argThat; 60 import static org.mockito.ArgumentMatchers.eq; 61 import static org.mockito.Mockito.atLeastOnce; 62 import static org.mockito.Mockito.doNothing; 63 import static org.mockito.Mockito.doReturn; 64 import static org.mockito.Mockito.inOrder; 65 import static org.mockito.Mockito.mock; 66 import static org.mockito.Mockito.never; 67 import static org.mockito.Mockito.reset; 68 import static org.mockito.Mockito.spy; 69 import static org.mockito.Mockito.times; 70 import static org.mockito.Mockito.verify; 71 import static org.mockito.Mockito.verifyNoMoreInteractions; 72 import static org.mockito.Mockito.when; 73 74 import android.content.Context; 75 import android.content.pm.PackageManager; 76 import android.net.InetAddresses; 77 import android.net.IpSecManager; 78 import android.net.IpSecManager.UdpEncapsulationSocket; 79 import android.net.IpSecTransform; 80 import android.net.LinkAddress; 81 import android.net.ipsec.test.ike.ChildSaProposal; 82 import android.net.ipsec.test.ike.ChildSessionCallback; 83 import android.net.ipsec.test.ike.ChildSessionConfiguration; 84 import android.net.ipsec.test.ike.ChildSessionParams; 85 import android.net.ipsec.test.ike.IkeManager; 86 import android.net.ipsec.test.ike.IkeTrafficSelector; 87 import android.net.ipsec.test.ike.SaProposal; 88 import android.net.ipsec.test.ike.TunnelModeChildSessionParams; 89 import android.net.ipsec.test.ike.exceptions.IkeException; 90 import android.net.ipsec.test.ike.exceptions.IkeInternalException; 91 import android.net.ipsec.test.ike.exceptions.InvalidKeException; 92 import android.net.ipsec.test.ike.exceptions.InvalidSyntaxException; 93 import android.net.ipsec.test.ike.exceptions.NoAdditionalSasException; 94 import android.net.ipsec.test.ike.exceptions.NoValidProposalChosenException; 95 import android.os.Build; 96 import android.os.Handler; 97 import android.os.Message; 98 import android.os.test.TestLooper; 99 100 import androidx.test.InstrumentationRegistry; 101 102 import com.android.internal.net.TestUtils; 103 import com.android.internal.net.ipsec.test.ike.ChildSessionStateMachine.CreateChildSaHelper; 104 import com.android.internal.net.ipsec.test.ike.ChildSessionStateMachine.IChildSessionSmCallback; 105 import com.android.internal.net.ipsec.test.ike.ChildSessionStateMachine.IdleWithDeferredRequest; 106 import com.android.internal.net.ipsec.test.ike.SaRecord.ChildSaRecord; 107 import com.android.internal.net.ipsec.test.ike.SaRecord.ChildSaRecordConfig; 108 import com.android.internal.net.ipsec.test.ike.SaRecord.ISaRecordHelper; 109 import com.android.internal.net.ipsec.test.ike.SaRecord.SaLifetimeAlarmScheduler; 110 import com.android.internal.net.ipsec.test.ike.SaRecord.SaRecordHelper; 111 import com.android.internal.net.ipsec.test.ike.crypto.IkeCipher; 112 import com.android.internal.net.ipsec.test.ike.crypto.IkeMacIntegrity; 113 import com.android.internal.net.ipsec.test.ike.crypto.IkeMacPrf; 114 import com.android.internal.net.ipsec.test.ike.message.IkeConfigPayload; 115 import com.android.internal.net.ipsec.test.ike.message.IkeConfigPayload.ConfigAttribute; 116 import com.android.internal.net.ipsec.test.ike.message.IkeConfigPayload.ConfigAttributeIpv4Address; 117 import com.android.internal.net.ipsec.test.ike.message.IkeConfigPayload.ConfigAttributeIpv4Netmask; 118 import com.android.internal.net.ipsec.test.ike.message.IkeDeletePayload; 119 import com.android.internal.net.ipsec.test.ike.message.IkeKePayload; 120 import com.android.internal.net.ipsec.test.ike.message.IkeNoncePayload; 121 import com.android.internal.net.ipsec.test.ike.message.IkeNotifyPayload; 122 import com.android.internal.net.ipsec.test.ike.message.IkePayload; 123 import com.android.internal.net.ipsec.test.ike.message.IkeSaPayload; 124 import com.android.internal.net.ipsec.test.ike.message.IkeSaPayload.DhGroupTransform; 125 import com.android.internal.net.ipsec.test.ike.message.IkeSaPayload.EncryptionTransform; 126 import com.android.internal.net.ipsec.test.ike.message.IkeSaPayload.IntegrityTransform; 127 import com.android.internal.net.ipsec.test.ike.message.IkeSaPayload.PrfTransform; 128 import com.android.internal.net.ipsec.test.ike.message.IkeTestUtils; 129 import com.android.internal.net.ipsec.test.ike.message.IkeTsPayload; 130 import com.android.internal.net.ipsec.test.ike.testutils.MockIpSecTestUtils; 131 import com.android.internal.net.ipsec.test.ike.utils.IState; 132 import com.android.internal.net.ipsec.test.ike.utils.IkeMetrics; 133 import com.android.internal.net.ipsec.test.ike.utils.IpSecSpiGenerator; 134 import com.android.internal.net.ipsec.test.ike.utils.RandomnessFactory; 135 import com.android.internal.net.utils.test.Log; 136 import com.android.server.IpSecService; 137 import com.android.testutils.DevSdkIgnoreRule; 138 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; 139 140 import org.junit.After; 141 import org.junit.Before; 142 import org.junit.Ignore; 143 import org.junit.Rule; 144 import org.junit.Test; 145 import org.mockito.ArgumentCaptor; 146 import org.mockito.InOrder; 147 148 import java.net.Inet4Address; 149 import java.net.Inet6Address; 150 import java.net.InetAddress; 151 import java.security.GeneralSecurityException; 152 import java.util.ArrayList; 153 import java.util.Arrays; 154 import java.util.List; 155 import java.util.concurrent.Executor; 156 157 public final class ChildSessionStateMachineTest extends IkeSessionTestBase { 158 private static final String TAG = "ChildSessionStateMachineTest"; 159 160 @Rule public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule(); 161 162 private static final Inet4Address LOCAL_ADDRESS = 163 (Inet4Address) InetAddresses.parseNumericAddress("192.0.2.200"); 164 private static final Inet4Address UPDATED_LOCAL_ADDRESS = 165 (Inet4Address) InetAddresses.parseNumericAddress("192.0.2.201"); 166 private static final Inet4Address REMOTE_ADDRESS = 167 (Inet4Address) InetAddresses.parseNumericAddress("192.0.2.100"); 168 private static final Inet4Address INTERNAL_ADDRESS = 169 (Inet4Address) InetAddresses.parseNumericAddress("203.0.113.100"); 170 private static final Inet6Address LOCAL_ADDRESS_6 = 171 (Inet6Address) InetAddresses.parseNumericAddress("2001:db8::1"); 172 private static final Inet6Address REMOTE_ADDRESS_6 = 173 (Inet6Address) InetAddresses.parseNumericAddress("2001:db8::2"); 174 175 private static final int IPV4_PREFIX_LEN = 32; 176 177 private static final String IKE_AUTH_RESP_SA_PAYLOAD = 178 "2c00002c0000002801030403cae7019f0300000c0100000c800e0080" 179 + "03000008030000020000000805000000"; 180 private static final String REKEY_CHILD_RESP_SA_PAYLOAD = 181 "2800002c0000002801030403cd1736b30300000c0100000c800e0080" 182 + "03000008030000020000000805000000"; 183 private static final String REKEY_CHILD_REQ_SA_PAYLOAD = 184 "2800002c0000002801030403c88336490300000c0100000c800e0080" 185 + "03000008030000020000000805000000"; 186 private static final String REKEY_CHILD_UNACCEPTABLE_REQ_SA_PAYLOAD = 187 "2800002c0000002801030403c88336490300000c0100000c800e00c0" 188 + "03000008030000020000000805000000"; 189 190 private static final int CURRENT_CHILD_SA_SPI_IN = 0x2ad4c0a2; 191 private static final int CURRENT_CHILD_SA_SPI_OUT = 0xcae7019f; 192 193 private static final int LOCAL_INIT_NEW_CHILD_SA_SPI_IN = 0x57a09b0f; 194 private static final int LOCAL_INIT_NEW_CHILD_SA_SPI_OUT = 0xcd1736b3; 195 196 private static final int REMOTE_INIT_NEW_CHILD_SA_SPI_IN = 0xd2d01795; 197 private static final int REMOTE_INIT_NEW_CHILD_SA_SPI_OUT = 0xc8833649; 198 199 private static final String IKE_SK_D_HEX_STRING = "C86B56EFCF684DCC2877578AEF3137167FE0EBF6"; 200 private static final byte[] SK_D = TestUtils.hexStringToByteArray(IKE_SK_D_HEX_STRING); 201 202 private static final int KEY_LEN_IKE_SKD = 20; 203 204 private static final int IKE_SESSION_UNIQUE_ID = 1; 205 private static final int IKE_DH_GROUP = SaProposal.DH_GROUP_4096_BIT_MODP; 206 207 private IkeMacPrf mIkePrf; 208 209 private Context mContext; 210 private Handler mMockIkeHandler; 211 private PackageManager mMockPackageManager; 212 private IpSecService mMockIpSecService; 213 private IpSecManager mMockIpSecManager; 214 private UdpEncapsulationSocket mMockUdpEncapSocket; 215 216 private TestLooper mLooper; 217 private RandomnessFactory mMockRandomFactory; 218 private IpSecSpiGenerator mIpSecSpiGenerator; 219 private ChildSessionStateMachine mChildSessionStateMachine; 220 221 private List<IkePayload> mFirstSaReqPayloads = new ArrayList<>(); 222 private List<IkePayload> mFirstSaRespPayloads = new ArrayList<>(); 223 224 private ChildSaRecord mSpyCurrentChildSaRecord; 225 private ChildSaRecord mSpyLocalInitNewChildSaRecord; 226 private ChildSaRecord mSpyRemoteInitNewChildSaRecord; 227 228 private Log mSpyIkeLog; 229 230 private ISaRecordHelper mMockSaRecordHelper; 231 232 private ChildSessionParams mChildSessionParams; 233 private EncryptionTransform mChildEncryptionTransform; 234 private IntegrityTransform mChildIntegrityTransform; 235 private DhGroupTransform mChildDhGroupTransform; 236 237 private ChildSaProposal mMockNegotiatedProposal; 238 239 private Executor mSpyUserCbExecutor; 240 private ChildSessionCallback mMockChildSessionCallback; 241 private IChildSessionSmCallback mMockChildSessionSmCallback; 242 243 private ArgumentCaptor<ChildSaRecordConfig> mChildSaRecordConfigCaptor = 244 ArgumentCaptor.forClass(ChildSaRecordConfig.class); 245 private ArgumentCaptor<List<IkePayload>> mPayloadListCaptor = 246 ArgumentCaptor.forClass(List.class); 247 private ArgumentCaptor<ChildSessionConfiguration> mChildConfigCaptor = 248 ArgumentCaptor.forClass(ChildSessionConfiguration.class); 249 ChildSessionStateMachineTest()250 public ChildSessionStateMachineTest() { 251 mMockSaRecordHelper = mock(SaRecord.ISaRecordHelper.class); 252 mMockChildSessionSmCallback = mock(IChildSessionSmCallback.class); 253 254 mChildEncryptionTransform = 255 new EncryptionTransform( 256 SaProposal.ENCRYPTION_ALGORITHM_AES_CBC, SaProposal.KEY_LEN_AES_128); 257 mChildIntegrityTransform = 258 new IntegrityTransform(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96); 259 260 mChildDhGroupTransform = new DhGroupTransform(SaProposal.DH_GROUP_1024_BIT_MODP); 261 } 262 263 @Before setup()264 public void setup() throws Exception { 265 mSpyIkeLog = TestUtils.makeSpyLogThrowExceptionForWtf(TAG); 266 IkeManager.setIkeLog(mSpyIkeLog); 267 268 mIkePrf = IkeMacPrf.create(new PrfTransform(SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1)); 269 270 mContext = spy(InstrumentationRegistry.getContext()); 271 mMockIkeHandler = mock(Handler.class); 272 when(mMockIkeHandler.obtainMessage(anyInt(), anyInt(), anyInt(), any())) 273 .thenReturn(mock(Message.class)); 274 275 mMockPackageManager = mock(PackageManager.class); 276 doReturn(mMockPackageManager).when(mContext).getPackageManager(); 277 278 mMockIpSecService = mock(IpSecService.class); 279 mMockIpSecManager = new IpSecManager(mContext, mMockIpSecService); 280 mMockUdpEncapSocket = mock(UdpEncapsulationSocket.class); 281 282 mIpSecSpiGenerator = new IpSecSpiGenerator(mMockIpSecManager, createMockRandomFactory()); 283 284 mMockNegotiatedProposal = mock(ChildSaProposal.class); 285 286 mSpyUserCbExecutor = 287 spy( 288 (command) -> { 289 command.run(); 290 }); 291 292 mMockChildSessionCallback = mock(ChildSessionCallback.class); 293 mChildSessionParams = buildChildSessionParams(); 294 295 // Setup thread and looper 296 mLooper = new TestLooper(); 297 mChildSessionStateMachine = buildChildSession(mChildSessionParams); 298 mChildSessionStateMachine.setDbg(true); 299 SaRecord.setSaRecordHelper(mMockSaRecordHelper); 300 301 setUpFirstSaNegoPayloadLists(); 302 setUpChildSaRecords(); 303 304 mChildSessionStateMachine.start(); 305 } 306 307 @After tearDown()308 public void tearDown() { 309 mChildSessionStateMachine.setDbg(false); 310 IkeManager.resetIkeLog(); 311 SaRecord.setSaRecordHelper(new SaRecordHelper()); 312 } 313 buildSaProposal()314 private ChildSaProposal buildSaProposal() throws Exception { 315 return new ChildSaProposal.Builder() 316 .addEncryptionAlgorithm( 317 SaProposal.ENCRYPTION_ALGORITHM_AES_CBC, SaProposal.KEY_LEN_AES_128) 318 .addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96) 319 .build(); 320 } 321 buildChildSessionParams()322 private ChildSessionParams buildChildSessionParams() throws Exception { 323 return new TunnelModeChildSessionParams.Builder() 324 .addSaProposal(buildSaProposal()) 325 .addInternalAddressRequest(AF_INET) 326 .addInternalAddressRequest(INTERNAL_ADDRESS) 327 .build(); 328 } 329 setUpChildSaRecords()330 private void setUpChildSaRecords() { 331 mSpyCurrentChildSaRecord = 332 makeSpyChildSaRecord(CURRENT_CHILD_SA_SPI_IN, CURRENT_CHILD_SA_SPI_OUT); 333 mSpyLocalInitNewChildSaRecord = 334 makeSpyChildSaRecord( 335 LOCAL_INIT_NEW_CHILD_SA_SPI_IN, LOCAL_INIT_NEW_CHILD_SA_SPI_OUT); 336 mSpyRemoteInitNewChildSaRecord = 337 makeSpyChildSaRecord( 338 REMOTE_INIT_NEW_CHILD_SA_SPI_IN, REMOTE_INIT_NEW_CHILD_SA_SPI_OUT); 339 } 340 setUpSpiResource(InetAddress address, int spiRequested)341 private void setUpSpiResource(InetAddress address, int spiRequested) throws Exception { 342 when(mMockIpSecService.allocateSecurityParameterIndex( 343 eq(address.getHostAddress()), anyInt(), any())) 344 .thenReturn(MockIpSecTestUtils.buildDummyIpSecSpiResponse(spiRequested)); 345 } 346 setUpFirstSaNegoPayloadLists()347 private void setUpFirstSaNegoPayloadLists() throws Exception { 348 // Build locally generated SA payload that has its SPI resource allocated. 349 setUpSpiResource(LOCAL_ADDRESS, CURRENT_CHILD_SA_SPI_IN); 350 IkeSaPayload reqSaPayload = 351 IkeSaPayload.createChildSaRequestPayload( 352 mChildSessionParams.getSaProposalsInternal(), 353 mIpSecSpiGenerator, 354 LOCAL_ADDRESS); 355 mFirstSaReqPayloads.add(reqSaPayload); 356 357 // Build a remotely generated SA payload whoes SPI resource has not been allocated. 358 setUpSpiResource(REMOTE_ADDRESS, CURRENT_CHILD_SA_SPI_OUT); 359 IkeSaPayload respSaPayload = 360 (IkeSaPayload) 361 IkeTestUtils.hexStringToIkePayload( 362 IkePayload.PAYLOAD_TYPE_SA, true, IKE_AUTH_RESP_SA_PAYLOAD); 363 mFirstSaRespPayloads.add(respSaPayload); 364 365 // Build TS Payloads 366 IkeTsPayload tsInitPayload = 367 new IkeTsPayload( 368 true /*isInitiator*/, 369 mChildSessionParams.getInboundTrafficSelectorsInternal()); 370 IkeTsPayload tsRespPayload = 371 new IkeTsPayload( 372 false /*isInitiator*/, 373 mChildSessionParams.getOutboundTrafficSelectorsInternal()); 374 375 mFirstSaReqPayloads.add(tsInitPayload); 376 mFirstSaReqPayloads.add(tsRespPayload); 377 mFirstSaRespPayloads.add(tsInitPayload); 378 mFirstSaRespPayloads.add(tsRespPayload); 379 380 // Build Nonce Payloads 381 mFirstSaReqPayloads.add(new IkeNoncePayload(createMockRandomFactory())); 382 mFirstSaRespPayloads.add(new IkeNoncePayload(createMockRandomFactory())); 383 384 // Build Config Request Payload 385 List<ConfigAttribute> attrReqList = new ArrayList<>(); 386 attrReqList.add(new ConfigAttributeIpv4Address(INTERNAL_ADDRESS)); 387 attrReqList.add(new ConfigAttributeIpv4Netmask()); 388 mFirstSaReqPayloads.add(new IkeConfigPayload(false /*isReply*/, attrReqList)); 389 390 // Build Config Reply Payload 391 List<ConfigAttribute> attrRespList = new ArrayList<>(); 392 attrRespList.add(new ConfigAttributeIpv4Address(INTERNAL_ADDRESS)); 393 mFirstSaRespPayloads.add(new IkeConfigPayload(true /*isReply*/, attrRespList)); 394 } 395 makeSpyChildSaRecord(int inboundSpi, int outboundSpi)396 private ChildSaRecord makeSpyChildSaRecord(int inboundSpi, int outboundSpi) { 397 ChildSaRecord child = 398 spy( 399 new ChildSaRecord( 400 inboundSpi, 401 outboundSpi, 402 true /*localInit*/, 403 null, 404 null, 405 null, 406 null, 407 null, 408 null, 409 mock(IpSecTransform.class), 410 mock(IpSecTransform.class), 411 mock(SaLifetimeAlarmScheduler.class))); 412 doNothing().when(child).close(); 413 return child; 414 } 415 quitAndVerify()416 private void quitAndVerify() { 417 mChildSessionStateMachine.mCurrentChildSaRecord = null; 418 mChildSessionStateMachine.mLocalInitNewChildSaRecord = null; 419 mChildSessionStateMachine.mRemoteInitNewChildSaRecord = null; 420 421 reset(mMockChildSessionSmCallback); 422 mChildSessionStateMachine.quit(); 423 mLooper.dispatchAll(); 424 425 verify(mMockChildSessionSmCallback).onProcedureFinished(mChildSessionStateMachine); 426 verify(mMockChildSessionSmCallback).onChildSessionClosed(mMockChildSessionCallback); 427 } 428 verifyChildSaRecordConfig( ChildSaRecordConfig childSaRecordConfig, int initSpi, int respSpi, boolean isLocalInit)429 private void verifyChildSaRecordConfig( 430 ChildSaRecordConfig childSaRecordConfig, 431 int initSpi, 432 int respSpi, 433 boolean isLocalInit) { 434 verifyChildSaRecordConfig( 435 childSaRecordConfig, 436 initSpi, 437 respSpi, 438 isLocalInit, 439 LOCAL_ADDRESS, 440 REMOTE_ADDRESS, 441 mMockUdpEncapSocket); 442 } 443 verifyChildSaRecordConfig( ChildSaRecordConfig childSaRecordConfig, int initSpi, int respSpi, boolean isLocalInit, InetAddress localAddress, InetAddress remoteAddress, UdpEncapsulationSocket newEncapSocket)444 private void verifyChildSaRecordConfig( 445 ChildSaRecordConfig childSaRecordConfig, 446 int initSpi, 447 int respSpi, 448 boolean isLocalInit, 449 InetAddress localAddress, 450 InetAddress remoteAddress, 451 UdpEncapsulationSocket newEncapSocket) { 452 assertEquals(mContext, childSaRecordConfig.context); 453 assertEquals(initSpi, childSaRecordConfig.initSpi.getSpi()); 454 assertEquals(respSpi, childSaRecordConfig.respSpi.getSpi()); 455 456 if (isLocalInit) { 457 assertEquals(localAddress, childSaRecordConfig.initAddress); 458 assertEquals(remoteAddress, childSaRecordConfig.respAddress); 459 } else { 460 assertEquals(remoteAddress, childSaRecordConfig.initAddress); 461 assertEquals(localAddress, childSaRecordConfig.respAddress); 462 } 463 464 assertEquals(newEncapSocket, childSaRecordConfig.udpEncapSocket); 465 assertEquals(mIkePrf, childSaRecordConfig.ikePrf); 466 assertArrayEquals(SK_D, childSaRecordConfig.skD); 467 assertFalse(childSaRecordConfig.isTransport); 468 assertEquals(isLocalInit, childSaRecordConfig.isLocalInit); 469 assertTrue(childSaRecordConfig.hasIntegrityAlgo); 470 assertNotNull(childSaRecordConfig.saLifetimeAlarmScheduler); 471 } 472 verifyNotifyUsersCreateIpSecSa( ChildSaRecord childSaRecord, boolean expectInbound)473 private void verifyNotifyUsersCreateIpSecSa( 474 ChildSaRecord childSaRecord, boolean expectInbound) { 475 IpSecTransform transform = 476 expectInbound 477 ? childSaRecord.getInboundIpSecTransform() 478 : childSaRecord.getOutboundIpSecTransform(); 479 int direction = expectInbound ? IpSecManager.DIRECTION_IN : IpSecManager.DIRECTION_OUT; 480 481 verify(mMockChildSessionCallback).onIpSecTransformCreated(eq(transform), eq(direction)); 482 } 483 verifyInitCreateChildResp( List<IkePayload> reqPayloads, List<IkePayload> respPayloads)484 private void verifyInitCreateChildResp( 485 List<IkePayload> reqPayloads, List<IkePayload> respPayloads) throws Exception { 486 verify(mMockChildSessionSmCallback) 487 .onChildSaCreated( 488 mSpyCurrentChildSaRecord.getRemoteSpi(), mChildSessionStateMachine); 489 verify(mMockChildSessionSmCallback).onProcedureFinished(mChildSessionStateMachine); 490 assertTrue( 491 mChildSessionStateMachine.getCurrentState() 492 instanceof ChildSessionStateMachine.Idle); 493 494 // Validate negotiated SA proposal. 495 ChildSaProposal negotiatedProposal = mChildSessionStateMachine.mSaProposal; 496 assertNotNull(negotiatedProposal); 497 assertEquals( 498 new EncryptionTransform[] {mChildEncryptionTransform}, 499 negotiatedProposal.getEncryptionTransforms()); 500 assertEquals( 501 new IntegrityTransform[] {mChildIntegrityTransform}, 502 negotiatedProposal.getIntegrityTransforms()); 503 504 // Validate current ChildSaRecord 505 verify(mMockSaRecordHelper) 506 .makeChildSaRecord( 507 eq(reqPayloads), eq(respPayloads), mChildSaRecordConfigCaptor.capture()); 508 ChildSaRecordConfig childSaRecordConfig = mChildSaRecordConfigCaptor.getValue(); 509 510 verifyChildSaRecordConfig( 511 childSaRecordConfig, 512 CURRENT_CHILD_SA_SPI_IN, 513 CURRENT_CHILD_SA_SPI_OUT, 514 true /*isLocalInit*/); 515 516 assertEquals(mSpyCurrentChildSaRecord, mChildSessionStateMachine.mCurrentChildSaRecord); 517 518 verify(mMockChildSessionSmCallback) 519 .onChildSaCreated(anyInt(), eq(mChildSessionStateMachine)); 520 verify(mMockChildSessionSmCallback).onProcedureFinished(mChildSessionStateMachine); 521 assertTrue( 522 mChildSessionStateMachine.getCurrentState() 523 instanceof ChildSessionStateMachine.Idle); 524 525 // Verify users have been notified 526 verify(mSpyUserCbExecutor).execute(any(Runnable.class)); 527 verifyNotifyUsersCreateIpSecSa(mSpyCurrentChildSaRecord, true /*expectInbound*/); 528 verifyNotifyUsersCreateIpSecSa(mSpyCurrentChildSaRecord, false /*expectInbound*/); 529 verify(mMockChildSessionCallback).onOpened(mChildConfigCaptor.capture()); 530 531 // Verify Child Session Configuration 532 ChildSessionConfiguration sessionConfig = mChildConfigCaptor.getValue(); 533 verifyTsList( 534 Arrays.asList(mChildSessionParams.getInboundTrafficSelectorsInternal()), 535 sessionConfig.getInboundTrafficSelectors()); 536 verifyTsList( 537 Arrays.asList(mChildSessionParams.getOutboundTrafficSelectorsInternal()), 538 sessionConfig.getOutboundTrafficSelectors()); 539 540 List<LinkAddress> addrList = sessionConfig.getInternalAddresses(); 541 assertEquals(1, addrList.size()); 542 assertEquals(INTERNAL_ADDRESS, addrList.get(0).getAddress()); 543 assertEquals(IPV4_PREFIX_LEN, addrList.get(0).getPrefixLength()); 544 verifyIkeSaMetricsLogged( 545 1, 546 IkeMetrics.IKE_CALLER_UNKNOWN, 547 IkeMetrics.IKE_SESSION_TYPE_CHILD, 548 IkeMetrics.IKE_STATE_CHILD_CREATE_LOCAL_CREATE, 549 SaProposal.DH_GROUP_NONE, 550 IkeMetrics.ENCRYPTION_ALGORITHM_AES_CBC, 551 IkeMetrics.KEY_LEN_AES_128, 552 IkeMetrics.INTEGRITY_ALGORITHM_HMAC_SHA1_96, 553 IkeMetrics.PSEUDORANDOM_FUNCTION_UNSPECIFIED, 554 IkeMetrics.IKE_ERROR_NONE); 555 } 556 verifyTsList( List<IkeTrafficSelector> expectedList, List<IkeTrafficSelector> tsList)557 private void verifyTsList( 558 List<IkeTrafficSelector> expectedList, List<IkeTrafficSelector> tsList) { 559 assertEquals(expectedList.size(), tsList.size()); 560 for (int i = 0; i < expectedList.size(); i++) { 561 assertEquals(expectedList.get(i), tsList.get(i)); 562 } 563 } 564 565 @Ignore disableTestCreateFirstChild()566 public void disableTestCreateFirstChild() throws Exception { 567 doReturn(mSpyCurrentChildSaRecord) 568 .when(mMockSaRecordHelper) 569 .makeChildSaRecord(any(), any(), any()); 570 571 mChildSessionStateMachine.handleFirstChildExchange( 572 mFirstSaReqPayloads, 573 mFirstSaRespPayloads, 574 LOCAL_ADDRESS, 575 REMOTE_ADDRESS, 576 mMockUdpEncapSocket, 577 mIkePrf, 578 IKE_DH_GROUP, 579 SK_D); 580 mLooper.dispatchAll(); 581 582 verifyInitCreateChildResp(mFirstSaReqPayloads, mFirstSaRespPayloads); 583 584 quitAndVerify(); 585 } 586 validateCreateChild(boolean isFirstChild)587 private void validateCreateChild(boolean isFirstChild) { 588 assertEquals(mChildSessionStateMachine.mLocalAddress, LOCAL_ADDRESS); 589 assertEquals(mChildSessionStateMachine.mRemoteAddress, REMOTE_ADDRESS); 590 assertEquals(mChildSessionStateMachine.mUdpEncapSocket, mMockUdpEncapSocket); 591 assertEquals(mChildSessionStateMachine.mIkePrf, mIkePrf); 592 assertEquals(mChildSessionStateMachine.mIkeDhGroup, IKE_DH_GROUP); 593 assertEquals(mChildSessionStateMachine.mSkD, SK_D); 594 assertEquals(mChildSessionStateMachine.mIsFirstChild, isFirstChild); 595 } 596 597 @Test testHandleFirstChildExchange()598 public void testHandleFirstChildExchange() throws Exception { 599 mChildSessionStateMachine.handleFirstChildExchange( 600 mFirstSaReqPayloads, 601 mFirstSaRespPayloads, 602 LOCAL_ADDRESS, 603 REMOTE_ADDRESS, 604 mMockUdpEncapSocket, 605 mIkePrf, 606 IKE_DH_GROUP, 607 SK_D); 608 validateCreateChild(true /* isFirstChild */); 609 } 610 verifyOutboundCreatePayloadTypes( List<IkePayload> outboundPayloads, boolean isRekey)611 private void verifyOutboundCreatePayloadTypes( 612 List<IkePayload> outboundPayloads, boolean isRekey) { 613 assertNotNull( 614 IkePayload.getPayloadForTypeInProvidedList( 615 PAYLOAD_TYPE_SA, IkeSaPayload.class, outboundPayloads)); 616 assertNotNull( 617 IkePayload.getPayloadForTypeInProvidedList( 618 PAYLOAD_TYPE_TS_INITIATOR, IkeTsPayload.class, outboundPayloads)); 619 assertNotNull( 620 IkePayload.getPayloadForTypeInProvidedList( 621 PAYLOAD_TYPE_TS_RESPONDER, IkeTsPayload.class, outboundPayloads)); 622 assertNotNull( 623 IkePayload.getPayloadForTypeInProvidedList( 624 PAYLOAD_TYPE_NONCE, IkeNoncePayload.class, outboundPayloads)); 625 assertNull( 626 IkePayload.getPayloadForTypeInProvidedList( 627 PAYLOAD_TYPE_KE, IkeKePayload.class, outboundPayloads)); 628 629 IkeConfigPayload configPayload = 630 IkePayload.getPayloadForTypeInProvidedList( 631 PAYLOAD_TYPE_CP, IkeConfigPayload.class, outboundPayloads); 632 if (isRekey) { 633 assertNull(configPayload); 634 } else { 635 assertNotNull(configPayload); 636 assertEquals(IkeConfigPayload.CONFIG_TYPE_REQUEST, configPayload.configType); 637 } 638 } 639 checkCreateChildAndGetRequest()640 private List<IkePayload> checkCreateChildAndGetRequest() throws Exception { 641 doReturn(mSpyCurrentChildSaRecord) 642 .when(mMockSaRecordHelper) 643 .makeChildSaRecord(any(), any(), any()); 644 645 mChildSessionStateMachine.createChildSession( 646 LOCAL_ADDRESS, REMOTE_ADDRESS, mMockUdpEncapSocket, mIkePrf, IKE_DH_GROUP, SK_D); 647 mLooper.dispatchAll(); 648 649 // Validate outbound payload list 650 verify(mMockChildSessionSmCallback) 651 .onOutboundPayloadsReady( 652 eq(EXCHANGE_TYPE_CREATE_CHILD_SA), 653 eq(false), 654 mPayloadListCaptor.capture(), 655 eq(mChildSessionStateMachine)); 656 657 List<IkePayload> reqPayloadList = mPayloadListCaptor.getValue(); 658 verifyOutboundCreatePayloadTypes(reqPayloadList, false /*isRekey*/); 659 assertTrue( 660 IkePayload.getPayloadListForTypeInProvidedList( 661 PAYLOAD_TYPE_NOTIFY, IkeNotifyPayload.class, reqPayloadList) 662 .isEmpty()); 663 664 mChildSessionStateMachine.receiveResponse( 665 EXCHANGE_TYPE_CREATE_CHILD_SA, mFirstSaRespPayloads); 666 mLooper.dispatchAll(); 667 668 return reqPayloadList; 669 } 670 671 @Test testCreateChild()672 public void testCreateChild() throws Exception { 673 List<IkePayload> reqPayloadList = checkCreateChildAndGetRequest(); 674 validateCreateChild(false /* isFirstChild */); 675 676 verifyInitCreateChildResp(reqPayloadList, mFirstSaRespPayloads); 677 quitAndVerify(); 678 } 679 680 @Test testCreateChildExecuteCbAfterKillSession()681 public void testCreateChildExecuteCbAfterKillSession() throws Exception { 682 mChildSessionStateMachine.quitNow(); 683 mLooper.dispatchAll(); 684 685 LateExecuteExecutor lateExecutor = spy(new LateExecuteExecutor()); 686 mChildSessionStateMachine = buildAndStartChildSession(lateExecutor); 687 688 List<IkePayload> reqPayloadList = checkCreateChildAndGetRequest(); 689 690 mChildSessionStateMachine.killSession(); 691 mLooper.dispatchAll(); 692 693 lateExecutor.actuallyExecute(); 694 695 // Verify users have been notified 696 verifyNotifyUsersCreateIpSecSa(mSpyCurrentChildSaRecord, true /*expectInbound*/); 697 verifyNotifyUsersCreateIpSecSa(mSpyCurrentChildSaRecord, false /*expectInbound*/); 698 verify(mMockChildSessionCallback).onOpened(any(ChildSessionConfiguration.class)); 699 } 700 verifyChildMetricsLogged(int stateCode, int exceptionCode)701 private void verifyChildMetricsLogged(int stateCode, int exceptionCode) { 702 verifyMetricsLogged(IkeMetrics.IKE_SESSION_TYPE_CHILD, stateCode, exceptionCode); 703 } 704 verifyHandleFatalErrorAndQuit( IState state, Class<T> exceptionClass, int metricsExceptionType)705 private <T extends IkeException> void verifyHandleFatalErrorAndQuit( 706 IState state, Class<T> exceptionClass, int metricsExceptionType) { 707 assertNull(mChildSessionStateMachine.getCurrentState()); 708 verify(mMockChildSessionSmCallback).onProcedureFinished(mChildSessionStateMachine); 709 verify(mMockChildSessionSmCallback).onChildSessionClosed(mMockChildSessionCallback); 710 711 verify(mMockChildSessionCallback).onClosedWithException(any(exceptionClass)); 712 verifyChildMetricsLogged(getStateCode(state), metricsExceptionType); 713 } 714 createChildSessionAndReceiveErrorNotification(int notifyType)715 private void createChildSessionAndReceiveErrorNotification(int notifyType) throws Exception { 716 // Send out Create request 717 mChildSessionStateMachine.createChildSession( 718 LOCAL_ADDRESS, REMOTE_ADDRESS, mMockUdpEncapSocket, mIkePrf, IKE_DH_GROUP, SK_D); 719 mLooper.dispatchAll(); 720 721 // Receive error notification in Create response 722 IkeNotifyPayload notifyPayload = new IkeNotifyPayload(notifyType); 723 List<IkePayload> respPayloads = new ArrayList<>(); 724 respPayloads.add(notifyPayload); 725 mChildSessionStateMachine.receiveResponse(EXCHANGE_TYPE_CREATE_CHILD_SA, respPayloads); 726 mLooper.dispatchAll(); 727 } 728 729 @Test testCreateChildHandlesErrorNotifyResp()730 public void testCreateChildHandlesErrorNotifyResp() throws Exception { 731 createChildSessionAndReceiveErrorNotification(ERROR_TYPE_NO_PROPOSAL_CHOSEN); 732 733 // Verify no SPI for provisional Child was registered. 734 verify(mMockChildSessionSmCallback, never()) 735 .onChildSaCreated(anyInt(), eq(mChildSessionStateMachine)); 736 737 // Verify user was notified and state machine has quit. 738 verifyHandleFatalErrorAndQuit( 739 mChildSessionStateMachine.mCreateChildLocalCreate, 740 NoValidProposalChosenException.class, 741 IkeMetrics.IKE_ERROR_PROTOCOL_NO_PROPOSAL_CHOSEN); 742 } 743 744 @Test testCreateChildHandlesTemporaryFailure()745 public void testCreateChildHandlesTemporaryFailure() throws Exception { 746 createChildSessionAndReceiveErrorNotification(ERROR_TYPE_TEMPORARY_FAILURE); 747 748 // Verify no SPI for provisional Child was registered. 749 verify(mMockChildSessionSmCallback, never()) 750 .onChildSaCreated(anyInt(), eq(mChildSessionStateMachine)); 751 752 // Verify that Create Child re-enqueued 753 verify(mMockChildSessionSmCallback) 754 .scheduleRetryLocalRequest( 755 argThat( 756 childLocalRequest -> 757 childLocalRequest.procedureType 758 == CMD_LOCAL_REQUEST_CREATE_CHILD)); 759 760 assertTrue( 761 mChildSessionStateMachine.getCurrentState() 762 instanceof ChildSessionStateMachine.Initial); 763 } 764 765 @Test testCreateChildHandlesRespWithMissingPayload()766 public void testCreateChildHandlesRespWithMissingPayload() throws Exception { 767 // Send out Create request 768 mChildSessionStateMachine.createChildSession( 769 LOCAL_ADDRESS, REMOTE_ADDRESS, mMockUdpEncapSocket, mIkePrf, IKE_DH_GROUP, SK_D); 770 mLooper.dispatchAll(); 771 772 // Receive response with no Nonce Payload 773 List<IkePayload> respPayloads = new ArrayList<>(); 774 for (IkePayload payload : mFirstSaRespPayloads) { 775 if (IkePayload.PAYLOAD_TYPE_NONCE == payload.payloadType) continue; 776 respPayloads.add(payload); 777 } 778 mChildSessionStateMachine.receiveResponse(EXCHANGE_TYPE_CREATE_CHILD_SA, respPayloads); 779 mLooper.dispatchAll(); 780 781 // Verify SPI for provisional Child was registered and unregistered. 782 verify(mMockChildSessionSmCallback) 783 .onChildSaCreated(CURRENT_CHILD_SA_SPI_OUT, mChildSessionStateMachine); 784 verify(mMockChildSessionSmCallback).onChildSaDeleted(CURRENT_CHILD_SA_SPI_OUT); 785 786 // Verify user was notified and state machine has quit. 787 verifyHandleFatalErrorAndQuit( 788 mChildSessionStateMachine.mCreateChildLocalCreate, 789 InvalidSyntaxException.class, 790 IkeMetrics.IKE_ERROR_PROTOCOL_INVALID_SYNTAX); 791 } 792 793 @Test testCreateChildHandlesKeyCalculationFail()794 public void testCreateChildHandlesKeyCalculationFail() throws Exception { 795 // Throw exception when building ChildSaRecord 796 when(mMockSaRecordHelper.makeChildSaRecord(any(), any(), any())) 797 .thenThrow( 798 new GeneralSecurityException("testCreateChildHandlesKeyCalculationFail")); 799 800 // Send out and receive Create Child message 801 mChildSessionStateMachine.createChildSession( 802 LOCAL_ADDRESS, REMOTE_ADDRESS, mMockUdpEncapSocket, mIkePrf, IKE_DH_GROUP, SK_D); 803 mLooper.dispatchAll(); 804 mChildSessionStateMachine.receiveResponse( 805 EXCHANGE_TYPE_CREATE_CHILD_SA, mFirstSaRespPayloads); 806 mLooper.dispatchAll(); 807 808 // Verify SPI for provisional Child was registered and unregistered. 809 verify(mMockChildSessionSmCallback) 810 .onChildSaCreated(CURRENT_CHILD_SA_SPI_OUT, mChildSessionStateMachine); 811 verify(mMockChildSessionSmCallback).onChildSaDeleted(CURRENT_CHILD_SA_SPI_OUT); 812 813 // Verify user was notified and state machine has quit. 814 verifyHandleFatalErrorAndQuit( 815 mChildSessionStateMachine.mCreateChildLocalCreate, 816 IkeInternalException.class, 817 IkeMetrics.IKE_ERROR_INTERNAL); 818 } 819 setupIdleStateMachine()820 private void setupIdleStateMachine() throws Exception { 821 mChildSessionStateMachine.mLocalAddress = LOCAL_ADDRESS; 822 mChildSessionStateMachine.mRemoteAddress = REMOTE_ADDRESS; 823 mChildSessionStateMachine.mUdpEncapSocket = mMockUdpEncapSocket; 824 mChildSessionStateMachine.mIkePrf = mIkePrf; 825 mChildSessionStateMachine.mIkeDhGroup = IKE_DH_GROUP; 826 mChildSessionStateMachine.mSkD = SK_D; 827 828 mChildSessionStateMachine.mSaProposal = buildSaProposal(); 829 mChildSessionStateMachine.mChildCipher = mock(IkeCipher.class); 830 mChildSessionStateMachine.mChildIntegrity = mock(IkeMacIntegrity.class); 831 mChildSessionStateMachine.mLocalTs = 832 mChildSessionParams.getInboundTrafficSelectorsInternal(); 833 mChildSessionStateMachine.mRemoteTs = 834 mChildSessionParams.getOutboundTrafficSelectorsInternal(); 835 836 mChildSessionStateMachine.mCurrentChildSaRecord = mSpyCurrentChildSaRecord; 837 838 mChildSessionStateMachine.sendMessage( 839 CMD_FORCE_TRANSITION, mChildSessionStateMachine.mIdle); 840 mLooper.dispatchAll(); 841 842 assertTrue( 843 mChildSessionStateMachine.getCurrentState() 844 instanceof ChildSessionStateMachine.Idle); 845 } 846 makeDeletePayloads(int spi)847 private List<IkePayload> makeDeletePayloads(int spi) { 848 List<IkePayload> inboundPayloads = new ArrayList<>(1); 849 inboundPayloads.add(new IkeDeletePayload(new int[] {spi})); 850 return inboundPayloads; 851 } 852 verifyOutboundDeletePayload(int expectedSpi, boolean isResp)853 private void verifyOutboundDeletePayload(int expectedSpi, boolean isResp) { 854 verify(mMockChildSessionSmCallback) 855 .onOutboundPayloadsReady( 856 eq(EXCHANGE_TYPE_INFORMATIONAL), 857 eq(isResp), 858 mPayloadListCaptor.capture(), 859 eq(mChildSessionStateMachine)); 860 861 List<IkePayload> outPayloadList = mPayloadListCaptor.getValue(); 862 assertEquals(1, outPayloadList.size()); 863 864 List<IkeDeletePayload> deletePayloads = 865 IkePayload.getPayloadListForTypeInProvidedList( 866 PAYLOAD_TYPE_DELETE, IkeDeletePayload.class, outPayloadList); 867 assertEquals(1, deletePayloads.size()); 868 IkeDeletePayload deletePayload = deletePayloads.get(0); 869 assertEquals(expectedSpi, deletePayload.spisToDelete[0]); 870 } 871 verifyNotifyUserDeleteChildSa(ChildSaRecord childSaRecord)872 private void verifyNotifyUserDeleteChildSa(ChildSaRecord childSaRecord) { 873 verify(mMockChildSessionCallback) 874 .onIpSecTransformDeleted( 875 eq(childSaRecord.getInboundIpSecTransform()), 876 eq(IpSecManager.DIRECTION_IN)); 877 verify(mMockChildSessionCallback) 878 .onIpSecTransformDeleted( 879 eq(childSaRecord.getOutboundIpSecTransform()), 880 eq(IpSecManager.DIRECTION_OUT)); 881 } 882 verifyNotifyUsersDeleteSession(IState state)883 private void verifyNotifyUsersDeleteSession(IState state) { 884 verifyNotifyUsersDeleteSession(mSpyUserCbExecutor, state); 885 } 886 verifyNotifyUsersDeleteSession(Executor spyExecutor, IState state)887 private void verifyNotifyUsersDeleteSession(Executor spyExecutor, IState state) { 888 verifyNotifyUsersDeleteSession(spyExecutor, state, null, IkeMetrics.IKE_ERROR_NONE); 889 } 890 verifyNotifyUsersDeleteSession( Executor spyExecutor, IState state, Class<? extends IkeException> exceptionClass, int metricsExceptionType)891 private void verifyNotifyUsersDeleteSession( 892 Executor spyExecutor, 893 IState state, 894 Class<? extends IkeException> exceptionClass, 895 int metricsExceptionType) { 896 verify(spyExecutor, atLeastOnce()).execute(any(Runnable.class)); 897 verifyNotifyUserDeleteChildSa(mSpyCurrentChildSaRecord); 898 899 InOrder orderVerifier = inOrder(mMockChildSessionCallback); 900 orderVerifier 901 .verify(mMockChildSessionCallback, times(2)) 902 .onIpSecTransformDeleted(any(), anyInt()); 903 904 if (exceptionClass == null) { 905 orderVerifier.verify(mMockChildSessionCallback).onClosed(); 906 } else { 907 orderVerifier 908 .verify(mMockChildSessionCallback) 909 .onClosedWithException(any(exceptionClass)); 910 } 911 verifyChildMetricsLogged(getStateCode(state), metricsExceptionType); 912 } 913 914 @Test testDeleteChildLocal()915 public void testDeleteChildLocal() throws Exception { 916 setupIdleStateMachine(); 917 918 // Test initiating Delete request 919 mChildSessionStateMachine.deleteChildSession(); 920 mLooper.dispatchAll(); 921 922 assertTrue( 923 mChildSessionStateMachine.getCurrentState() 924 instanceof ChildSessionStateMachine.DeleteChildLocalDelete); 925 verifyOutboundDeletePayload(mSpyCurrentChildSaRecord.getLocalSpi(), false /*isResp*/); 926 927 // Test receiving Delete response 928 mChildSessionStateMachine.receiveResponse( 929 EXCHANGE_TYPE_INFORMATIONAL, 930 makeDeletePayloads(mSpyCurrentChildSaRecord.getRemoteSpi())); 931 mLooper.dispatchAll(); 932 933 assertNull(mChildSessionStateMachine.getCurrentState()); 934 935 verifyNotifyUsersDeleteSession(mChildSessionStateMachine.mDeleteChildLocalDelete); 936 } 937 938 @Test testDeleteChildLocalExecuteCbAfterKillSession()939 public void testDeleteChildLocalExecuteCbAfterKillSession() throws Exception { 940 mChildSessionStateMachine.quitNow(); 941 mLooper.dispatchAll(); 942 943 LateExecuteExecutor lateExecutor = spy(new LateExecuteExecutor()); 944 mChildSessionStateMachine = buildAndStartChildSession(lateExecutor); 945 946 setupIdleStateMachine(); 947 948 mChildSessionStateMachine.deleteChildSession(); 949 mChildSessionStateMachine.receiveResponse( 950 EXCHANGE_TYPE_INFORMATIONAL, 951 makeDeletePayloads(mSpyCurrentChildSaRecord.getRemoteSpi())); 952 mLooper.dispatchAll(); 953 954 assertNull(mChildSessionStateMachine.getCurrentState()); 955 956 lateExecutor.actuallyExecute(); 957 verifyNotifyUsersDeleteSession( 958 lateExecutor, mChildSessionStateMachine.mDeleteChildLocalDelete); 959 } 960 961 @Test testDeleteChildLocalHandlesInvalidResp()962 public void testDeleteChildLocalHandlesInvalidResp() throws Exception { 963 setupIdleStateMachine(); 964 965 // Test initiating Delete request 966 mChildSessionStateMachine.deleteChildSession(); 967 mLooper.dispatchAll(); 968 969 // Test receiving response with no Delete Payload 970 mChildSessionStateMachine.receiveResponse(EXCHANGE_TYPE_INFORMATIONAL, new ArrayList<>()); 971 mLooper.dispatchAll(); 972 973 assertNull(mChildSessionStateMachine.getCurrentState()); 974 verify(mMockChildSessionCallback).onClosedWithException(any(InvalidSyntaxException.class)); 975 verifyNotifyUserDeleteChildSa(mSpyCurrentChildSaRecord); 976 } 977 978 @Test testDeleteChildLocalInInitial()979 public void testDeleteChildLocalInInitial() throws Exception { 980 mChildSessionStateMachine.deleteChildSession(); 981 mLooper.dispatchAll(); 982 983 assertNull(mChildSessionStateMachine.getCurrentState()); 984 verify(mSpyUserCbExecutor).execute(any(Runnable.class)); 985 verify(mMockChildSessionCallback).onClosed(); 986 } 987 988 @Test testSimultaneousDeleteChild()989 public void testSimultaneousDeleteChild() throws Exception { 990 setupIdleStateMachine(); 991 992 mChildSessionStateMachine.deleteChildSession(); 993 mChildSessionStateMachine.receiveRequest( 994 IKE_EXCHANGE_SUBTYPE_DELETE_CHILD, 995 EXCHANGE_TYPE_INFORMATIONAL, 996 makeDeletePayloads(mSpyCurrentChildSaRecord.getRemoteSpi())); 997 mLooper.dispatchAll(); 998 999 verify(mMockChildSessionSmCallback) 1000 .onOutboundPayloadsReady( 1001 eq(EXCHANGE_TYPE_INFORMATIONAL), 1002 eq(true), 1003 mPayloadListCaptor.capture(), 1004 eq(mChildSessionStateMachine)); 1005 List<IkePayload> respPayloadList = mPayloadListCaptor.getValue(); 1006 assertTrue(respPayloadList.isEmpty()); 1007 1008 mChildSessionStateMachine.receiveResponse(EXCHANGE_TYPE_INFORMATIONAL, new ArrayList<>()); 1009 mLooper.dispatchAll(); 1010 1011 assertNull(mChildSessionStateMachine.getCurrentState()); 1012 1013 verifyNotifyUsersDeleteSession(mChildSessionStateMachine.mDeleteChildLocalDelete); 1014 } 1015 1016 @Test testReplyRekeyRequestDuringDeletion()1017 public void testReplyRekeyRequestDuringDeletion() throws Exception { 1018 setupIdleStateMachine(); 1019 1020 mChildSessionStateMachine.deleteChildSession(); 1021 mChildSessionStateMachine.receiveRequest( 1022 IKE_EXCHANGE_SUBTYPE_REKEY_CHILD, EXCHANGE_TYPE_CREATE_CHILD_SA, mock(List.class)); 1023 mLooper.dispatchAll(); 1024 1025 // Verify outbound response to Rekey Child request 1026 verify(mMockChildSessionSmCallback) 1027 .onOutboundPayloadsReady( 1028 eq(EXCHANGE_TYPE_INFORMATIONAL), 1029 eq(true), 1030 mPayloadListCaptor.capture(), 1031 eq(mChildSessionStateMachine)); 1032 List<IkePayload> respPayloadList = mPayloadListCaptor.getValue(); 1033 assertEquals(1, respPayloadList.size()); 1034 1035 IkeNotifyPayload notifyPayload = (IkeNotifyPayload) respPayloadList.get(0); 1036 assertEquals(ERROR_TYPE_TEMPORARY_FAILURE, notifyPayload.notifyType); 1037 assertEquals(0, notifyPayload.notifyData.length); 1038 1039 assertTrue( 1040 mChildSessionStateMachine.getCurrentState() 1041 instanceof ChildSessionStateMachine.DeleteChildLocalDelete); 1042 } 1043 1044 @Test testDeleteChildRemote()1045 public void testDeleteChildRemote() throws Exception { 1046 setupIdleStateMachine(); 1047 1048 mChildSessionStateMachine.receiveRequest( 1049 IKE_EXCHANGE_SUBTYPE_DELETE_CHILD, 1050 EXCHANGE_TYPE_INFORMATIONAL, 1051 makeDeletePayloads(mSpyCurrentChildSaRecord.getRemoteSpi())); 1052 mLooper.dispatchAll(); 1053 1054 assertNull(mChildSessionStateMachine.getCurrentState()); 1055 // Verify response 1056 verify(mMockChildSessionSmCallback) 1057 .onOutboundPayloadsReady( 1058 eq(EXCHANGE_TYPE_INFORMATIONAL), 1059 eq(true), 1060 mPayloadListCaptor.capture(), 1061 eq(mChildSessionStateMachine)); 1062 List<IkePayload> respPayloadList = mPayloadListCaptor.getValue(); 1063 1064 assertEquals(1, respPayloadList.size()); 1065 assertArrayEquals( 1066 new int[] {mSpyCurrentChildSaRecord.getLocalSpi()}, 1067 ((IkeDeletePayload) respPayloadList.get(0)).spisToDelete); 1068 1069 verifyNotifyUsersDeleteSession(mChildSessionStateMachine.mDeleteChildRemoteDelete); 1070 } 1071 verifyOutboundRekeySaPayload(List<IkePayload> outboundPayloads, boolean isResp)1072 private void verifyOutboundRekeySaPayload(List<IkePayload> outboundPayloads, boolean isResp) { 1073 IkeSaPayload saPayload = 1074 IkePayload.getPayloadForTypeInProvidedList( 1075 PAYLOAD_TYPE_SA, IkeSaPayload.class, outboundPayloads); 1076 assertEquals(isResp, saPayload.isSaResponse); 1077 assertEquals(1, saPayload.proposalList.size()); 1078 1079 IkeSaPayload.ChildProposal proposal = 1080 (IkeSaPayload.ChildProposal) saPayload.proposalList.get(0); 1081 assertEquals(1, proposal.number); // Must be 1-indexed 1082 assertEquals(mChildSessionStateMachine.mSaProposal, proposal.saProposal); 1083 } 1084 verifyOutboundRekeyNotifyPayload(List<IkePayload> outboundPayloads)1085 private void verifyOutboundRekeyNotifyPayload(List<IkePayload> outboundPayloads) { 1086 List<IkeNotifyPayload> notifyPayloads = 1087 IkePayload.getPayloadListForTypeInProvidedList( 1088 PAYLOAD_TYPE_NOTIFY, IkeNotifyPayload.class, outboundPayloads); 1089 assertEquals(1, notifyPayloads.size()); 1090 IkeNotifyPayload notifyPayload = notifyPayloads.get(0); 1091 assertEquals(NOTIFY_TYPE_REKEY_SA, notifyPayload.notifyType); 1092 assertEquals(PROTOCOL_ID_ESP, notifyPayload.protocolId); 1093 assertEquals(mSpyCurrentChildSaRecord.getLocalSpi(), notifyPayload.spi); 1094 } 1095 1096 @Test testRekeyChildLocalCreateSendsRequest()1097 public void testRekeyChildLocalCreateSendsRequest() throws Exception { 1098 setupIdleStateMachine(); 1099 1100 // Send Rekey-Create request 1101 mChildSessionStateMachine.rekeyChildSession(); 1102 mLooper.dispatchAll(); 1103 assertTrue( 1104 mChildSessionStateMachine.getCurrentState() 1105 instanceof ChildSessionStateMachine.RekeyChildLocalCreate); 1106 verify(mMockChildSessionSmCallback) 1107 .onOutboundPayloadsReady( 1108 eq(EXCHANGE_TYPE_CREATE_CHILD_SA), 1109 eq(false), 1110 mPayloadListCaptor.capture(), 1111 eq(mChildSessionStateMachine)); 1112 1113 // Verify outbound payload list 1114 List<IkePayload> reqPayloadList = mPayloadListCaptor.getValue(); 1115 verifyOutboundCreatePayloadTypes(reqPayloadList, true /*isRekey*/); 1116 1117 verifyOutboundRekeySaPayload(reqPayloadList, false /*isResp*/); 1118 verifyOutboundRekeyNotifyPayload(reqPayloadList); 1119 } 1120 makeInboundRekeyChildPayloads( int remoteSpi, String inboundSaHexString, boolean isLocalInitRekey)1121 private List<IkePayload> makeInboundRekeyChildPayloads( 1122 int remoteSpi, String inboundSaHexString, boolean isLocalInitRekey) throws Exception { 1123 IkeSaPayload saPayload = 1124 (IkeSaPayload) 1125 IkeTestUtils.hexStringToIkePayload( 1126 IkePayload.PAYLOAD_TYPE_SA, true, inboundSaHexString); 1127 1128 return makeInboundRekeyChildPayloads(remoteSpi, saPayload, isLocalInitRekey); 1129 } 1130 makeInboundRekeyChildPayloads( int remoteSpi, IkeSaPayload saPayload, boolean isLocalInitRekey)1131 private List<IkePayload> makeInboundRekeyChildPayloads( 1132 int remoteSpi, IkeSaPayload saPayload, boolean isLocalInitRekey) throws Exception { 1133 List<IkePayload> inboundPayloads = new ArrayList<>(); 1134 1135 inboundPayloads.add(saPayload); 1136 1137 // Build TS Payloads 1138 IkeTrafficSelector[] initTs = 1139 isLocalInitRekey 1140 ? mChildSessionStateMachine.mLocalTs 1141 : mChildSessionStateMachine.mRemoteTs; 1142 IkeTrafficSelector[] respTs = 1143 isLocalInitRekey 1144 ? mChildSessionStateMachine.mRemoteTs 1145 : mChildSessionStateMachine.mLocalTs; 1146 inboundPayloads.add(new IkeTsPayload(true /*isInitiator*/, initTs)); 1147 inboundPayloads.add(new IkeTsPayload(false /*isInitiator*/, respTs)); 1148 1149 // Build Nonce Payloads 1150 inboundPayloads.add(new IkeNoncePayload(createMockRandomFactory())); 1151 1152 if (isLocalInitRekey) { 1153 // Rekey-Create response without Notify-Rekey payload is valid. 1154 return inboundPayloads; 1155 } 1156 1157 // Build Rekey-Notification 1158 inboundPayloads.add( 1159 new IkeNotifyPayload( 1160 PROTOCOL_ID_ESP, 1161 mSpyCurrentChildSaRecord.getRemoteSpi(), 1162 NOTIFY_TYPE_REKEY_SA, 1163 new byte[0])); 1164 1165 return inboundPayloads; 1166 } 1167 receiveRekeyChildRequest()1168 private List<IkePayload> receiveRekeyChildRequest() throws Exception { 1169 List<IkePayload> rekeyReqPayloads = 1170 makeInboundRekeyChildPayloads( 1171 REMOTE_INIT_NEW_CHILD_SA_SPI_OUT, 1172 REKEY_CHILD_REQ_SA_PAYLOAD, 1173 false /*isLocalInitRekey*/); 1174 when(mMockSaRecordHelper.makeChildSaRecord( 1175 eq(rekeyReqPayloads), any(List.class), any(ChildSaRecordConfig.class))) 1176 .thenReturn(mSpyRemoteInitNewChildSaRecord); 1177 1178 // Receive rekey Child request 1179 mChildSessionStateMachine.receiveRequest( 1180 IKE_EXCHANGE_SUBTYPE_REKEY_CHILD, EXCHANGE_TYPE_CREATE_CHILD_SA, rekeyReqPayloads); 1181 mLooper.dispatchAll(); 1182 1183 return rekeyReqPayloads; 1184 } 1185 receiveRekeyChildResponse()1186 private List<IkePayload> receiveRekeyChildResponse() throws Exception { 1187 List<IkePayload> rekeyRespPayloads = 1188 makeInboundRekeyChildPayloads( 1189 LOCAL_INIT_NEW_CHILD_SA_SPI_OUT, 1190 REKEY_CHILD_RESP_SA_PAYLOAD, 1191 true /*isLocalInitRekey*/); 1192 when(mMockSaRecordHelper.makeChildSaRecord( 1193 any(List.class), eq(rekeyRespPayloads), any(ChildSaRecordConfig.class))) 1194 .thenReturn(mSpyLocalInitNewChildSaRecord); 1195 1196 mChildSessionStateMachine.receiveResponse(EXCHANGE_TYPE_CREATE_CHILD_SA, rekeyRespPayloads); 1197 mLooper.dispatchAll(); 1198 1199 return rekeyRespPayloads; 1200 } 1201 setupStateMachineAndSpiForLocalRekey()1202 private void setupStateMachineAndSpiForLocalRekey() throws Exception { 1203 setupStateMachineAndSpiForLocalRekey(LOCAL_ADDRESS, REMOTE_ADDRESS); 1204 } 1205 setupStateMachineAndSpiForLocalRekey( InetAddress updatedLocalAddress, InetAddress updatedRemoteAddress)1206 private void setupStateMachineAndSpiForLocalRekey( 1207 InetAddress updatedLocalAddress, InetAddress updatedRemoteAddress) throws Exception { 1208 setupIdleStateMachine(); 1209 setUpSpiResource(updatedLocalAddress, LOCAL_INIT_NEW_CHILD_SA_SPI_IN); 1210 setUpSpiResource(updatedRemoteAddress, LOCAL_INIT_NEW_CHILD_SA_SPI_OUT); 1211 } 1212 1213 @Test testRekeyChildLocalCreateValidatesResponse()1214 public void testRekeyChildLocalCreateValidatesResponse() throws Exception { 1215 setupStateMachineAndSpiForLocalRekey(); 1216 1217 // Send Rekey-Create request 1218 mChildSessionStateMachine.rekeyChildSession(); 1219 mLooper.dispatchAll(); 1220 1221 verifyRekeyChildLocalCreateHandlesResponse( 1222 ChildSessionStateMachine.RekeyChildLocalCreate.class, 1223 false /* isMobikeRekey */, 1224 LOCAL_ADDRESS, 1225 REMOTE_ADDRESS); 1226 } 1227 verifyRekeyChildLocalCreateHandlesResponse( Class<?> expectedState, boolean isMobikeRekey, InetAddress localAddress, InetAddress remoteAddress)1228 private void verifyRekeyChildLocalCreateHandlesResponse( 1229 Class<?> expectedState, 1230 boolean isMobikeRekey, 1231 InetAddress localAddress, 1232 InetAddress remoteAddress) 1233 throws Exception { 1234 verifyRekeyChildLocalCreateHandlesResponse( 1235 expectedState, isMobikeRekey, localAddress, remoteAddress, mMockUdpEncapSocket); 1236 } 1237 verifyRekeyChildLocalCreateHandlesResponse( Class<?> expectedState, boolean isMobikeRekey, InetAddress localAddress, InetAddress remoteAddress, UdpEncapsulationSocket newEncapSocket)1238 private void verifyRekeyChildLocalCreateHandlesResponse( 1239 Class<?> expectedState, 1240 boolean isMobikeRekey, 1241 InetAddress localAddress, 1242 InetAddress remoteAddress, 1243 UdpEncapsulationSocket newEncapSocket) 1244 throws Exception { 1245 assertTrue(expectedState.isInstance(mChildSessionStateMachine.getCurrentState())); 1246 1247 List<IkePayload> rekeyRespPayloads = receiveRekeyChildResponse(); 1248 verifyLocalRekeyCreateIsDone( 1249 rekeyRespPayloads, isMobikeRekey, localAddress, remoteAddress, newEncapSocket); 1250 } 1251 verifyLocalRekeyCreateIsDone( List<IkePayload> rekeyRespPayloads, boolean isMobikeRekey, InetAddress localAddress, InetAddress remoteAddress)1252 private void verifyLocalRekeyCreateIsDone( 1253 List<IkePayload> rekeyRespPayloads, 1254 boolean isMobikeRekey, 1255 InetAddress localAddress, 1256 InetAddress remoteAddress) 1257 throws Exception { 1258 verifyLocalRekeyCreateIsDone( 1259 rekeyRespPayloads, isMobikeRekey, localAddress, remoteAddress, mMockUdpEncapSocket); 1260 } 1261 verifyLocalRekeyCreateIsDone( List<IkePayload> rekeyRespPayloads, boolean isMobikeRekey, InetAddress localAddress, InetAddress remoteAddress, UdpEncapsulationSocket newEncapSocket)1262 private void verifyLocalRekeyCreateIsDone( 1263 List<IkePayload> rekeyRespPayloads, 1264 boolean isMobikeRekey, 1265 InetAddress localAddress, 1266 InetAddress remoteAddress, 1267 UdpEncapsulationSocket newEncapSocket) 1268 throws Exception { 1269 // Verify state transition 1270 assertTrue( 1271 mChildSessionStateMachine.getCurrentState() 1272 instanceof ChildSessionStateMachine.RekeyChildLocalDelete); 1273 1274 // Verify newly created ChildSaRecord 1275 assertEquals( 1276 mSpyLocalInitNewChildSaRecord, 1277 mChildSessionStateMachine.mLocalInitNewChildSaRecord); 1278 verify(mMockChildSessionSmCallback) 1279 .onChildSaCreated( 1280 eq(mSpyLocalInitNewChildSaRecord.getRemoteSpi()), 1281 eq(mChildSessionStateMachine)); 1282 1283 verify(mMockSaRecordHelper) 1284 .makeChildSaRecord( 1285 any(List.class), 1286 eq(rekeyRespPayloads), 1287 mChildSaRecordConfigCaptor.capture()); 1288 ChildSaRecordConfig childSaRecordConfig = mChildSaRecordConfigCaptor.getValue(); 1289 verifyChildSaRecordConfig( 1290 childSaRecordConfig, 1291 LOCAL_INIT_NEW_CHILD_SA_SPI_IN, 1292 LOCAL_INIT_NEW_CHILD_SA_SPI_OUT, 1293 true /*isLocalInit*/, 1294 localAddress, 1295 remoteAddress, 1296 newEncapSocket); 1297 1298 // Verify users have been notified 1299 verify(mSpyUserCbExecutor).execute(any(Runnable.class)); 1300 1301 if (isMobikeRekey) { 1302 verify(mMockChildSessionCallback) 1303 .onIpSecTransformsMigrated( 1304 mSpyLocalInitNewChildSaRecord.getInboundIpSecTransform(), 1305 mSpyLocalInitNewChildSaRecord.getOutboundIpSecTransform()); 1306 } else { 1307 verifyNotifyUsersCreateIpSecSa(mSpyLocalInitNewChildSaRecord, true /*expectInbound*/); 1308 verifyNotifyUsersCreateIpSecSa(mSpyLocalInitNewChildSaRecord, false /*expectInbound*/); 1309 } 1310 } 1311 1312 @Test testRekeyLocalCreateHandlesErrorNotifyResp()1313 public void testRekeyLocalCreateHandlesErrorNotifyResp() throws Exception { 1314 setupIdleStateMachine(); 1315 setUpSpiResource(LOCAL_ADDRESS, LOCAL_INIT_NEW_CHILD_SA_SPI_IN); 1316 1317 // Send Rekey-Create request 1318 mChildSessionStateMachine.rekeyChildSession(); 1319 mLooper.dispatchAll(); 1320 1321 // Receive error notification in Create response 1322 IkeNotifyPayload notifyPayload = new IkeNotifyPayload(ERROR_TYPE_INTERNAL_ADDRESS_FAILURE); 1323 List<IkePayload> respPayloads = new ArrayList<>(); 1324 respPayloads.add(notifyPayload); 1325 mChildSessionStateMachine.receiveResponse(EXCHANGE_TYPE_CREATE_CHILD_SA, respPayloads); 1326 mLooper.dispatchAll(); 1327 1328 // Verify rekey has been rescheduled and Child Session is alive 1329 verify(mSpyCurrentChildSaRecord).rescheduleRekey(eq(RETRY_INTERVAL_MS)); 1330 assertTrue( 1331 mChildSessionStateMachine.getCurrentState() 1332 instanceof ChildSessionStateMachine.Idle); 1333 1334 // Verify no SPI for provisional Child was registered. 1335 verify(mMockChildSessionSmCallback, never()) 1336 .onChildSaCreated(anyInt(), eq(mChildSessionStateMachine)); 1337 } 1338 verifySendOutboundIkeDeleteRequest()1339 private void verifySendOutboundIkeDeleteRequest() { 1340 verify(mMockChildSessionSmCallback) 1341 .onOutboundPayloadsReady( 1342 eq(EXCHANGE_TYPE_INFORMATIONAL), 1343 eq(false), 1344 mPayloadListCaptor.capture(), 1345 eq(mChildSessionStateMachine)); 1346 1347 List<IkePayload> reqPayloadList = mPayloadListCaptor.getValue(); 1348 1349 List<IkeDeletePayload> deletePayloads = 1350 IkePayload.getPayloadListForTypeInProvidedList( 1351 PAYLOAD_TYPE_DELETE, IkeDeletePayload.class, reqPayloadList); 1352 assertEquals(deletePayloads.size(), 1); 1353 1354 IkeDeletePayload deletePayload = deletePayloads.get(0); 1355 assertEquals(deletePayload.protocolId, IkePayload.PROTOCOL_ID_IKE); 1356 assertEquals(deletePayload.spisToDelete.length, 0); 1357 } 1358 verifyIkeSessionFatalErrorAndSendOutboundIkeDeletePayload( Class<T> exceptionClass, IState expectedState, int expectedErrorCode)1359 private <T extends IkeException> void verifyIkeSessionFatalErrorAndSendOutboundIkeDeletePayload( 1360 Class<T> exceptionClass, IState expectedState, int expectedErrorCode) { 1361 verifySendOutboundIkeDeleteRequest(); 1362 1363 // Verify callback onFatalIkeSessionError() has been invoked 1364 verify(mMockChildSessionSmCallback).onFatalIkeSessionError(any(exceptionClass)); 1365 1366 // Verify retry was not scheduled 1367 verify(mMockChildSessionSmCallback, never()).scheduleRetryLocalRequest(any()); 1368 1369 verifyMetricsLogged( 1370 IkeMetrics.IKE_SESSION_TYPE_CHILD, getStateCode(expectedState), expectedErrorCode); 1371 } 1372 1373 @Test testMobikeRekeyLocalCreateAndHandlesErrorNotifyResp()1374 public void testMobikeRekeyLocalCreateAndHandlesErrorNotifyResp() throws Exception { 1375 setupStateMachineAndSpiForLocalRekey(UPDATED_LOCAL_ADDRESS, REMOTE_ADDRESS); 1376 1377 // Send Mobike-Rekey-Create request 1378 mChildSessionStateMachine.performRekeyMigration( 1379 UPDATED_LOCAL_ADDRESS, REMOTE_ADDRESS, mMockUdpEncapSocket); 1380 mLooper.dispatchAll(); 1381 1382 // Receive error notification in Create response 1383 mChildSessionStateMachine.receiveResponse( 1384 EXCHANGE_TYPE_CREATE_CHILD_SA, 1385 Arrays.asList(new IkeNotifyPayload(ERROR_TYPE_NO_ADDITIONAL_SAS))); 1386 mLooper.dispatchAll(); 1387 1388 verifyIkeSessionFatalErrorAndSendOutboundIkeDeletePayload( 1389 NoAdditionalSasException.class, 1390 mChildSessionStateMachine.mMobikeRekeyChildLocalCreate, 1391 IkeMetrics.IKE_ERROR_PROTOCOL_NO_ADDITIONAL_SAS); 1392 } 1393 1394 @Test testMobikeRekeyLocalCreateAndHandlesMissingPayloadInResp()1395 public void testMobikeRekeyLocalCreateAndHandlesMissingPayloadInResp() throws Exception { 1396 setupStateMachineAndSpiForLocalRekey(UPDATED_LOCAL_ADDRESS, REMOTE_ADDRESS); 1397 1398 // Send Mobike-Rekey-Create request 1399 mChildSessionStateMachine.performRekeyMigration( 1400 UPDATED_LOCAL_ADDRESS, REMOTE_ADDRESS, mMockUdpEncapSocket); 1401 mLooper.dispatchAll(); 1402 1403 // Receive response with no SA Payload 1404 List<IkePayload> validRekeyRespPayloads = 1405 makeInboundRekeyChildPayloads( 1406 LOCAL_INIT_NEW_CHILD_SA_SPI_OUT, 1407 REKEY_CHILD_RESP_SA_PAYLOAD, 1408 true /*isLocalInitRekey*/); 1409 List<IkePayload> respPayloads = new ArrayList<>(); 1410 for (IkePayload payload : validRekeyRespPayloads) { 1411 if (IkePayload.PAYLOAD_TYPE_SA == payload.payloadType) continue; 1412 respPayloads.add(payload); 1413 } 1414 mChildSessionStateMachine.receiveResponse(EXCHANGE_TYPE_CREATE_CHILD_SA, respPayloads); 1415 mLooper.dispatchAll(); 1416 1417 verifyIkeSessionFatalErrorAndSendOutboundIkeDeletePayload( 1418 IkeException.class, 1419 mChildSessionStateMachine.mMobikeRekeyChildLocalCreate, 1420 IkeMetrics.IKE_ERROR_PROTOCOL_INVALID_SYNTAX); 1421 } 1422 1423 @Test testRekeyLocalCreateHandlesRekeyRequest()1424 public void testRekeyLocalCreateHandlesRekeyRequest() throws Exception { 1425 setupStateMachineAndSpiForLocalRekey(); 1426 1427 // Send Rekey-Create request 1428 mChildSessionStateMachine.rekeyChildSession(); 1429 mLooper.dispatchAll(); 1430 1431 receiveRekeyChildRequest(); 1432 1433 // Verify error notification was sent and state machine stays in the same state 1434 verifyOutboundErrorNotify(EXCHANGE_TYPE_INFORMATIONAL, ERROR_TYPE_TEMPORARY_FAILURE); 1435 assertTrue( 1436 mChildSessionStateMachine.getCurrentState() 1437 instanceof ChildSessionStateMachine.RekeyChildLocalCreate); 1438 1439 // Receive Rekey Create response and verify creation is done 1440 List<IkePayload> rekeyRespPayloads = receiveRekeyChildResponse(); 1441 verifyLocalRekeyCreateIsDone( 1442 rekeyRespPayloads, false /* isMobikeRekey */, LOCAL_ADDRESS, REMOTE_ADDRESS); 1443 verifyIkeSaMetricsLogged( 1444 1, 1445 IkeMetrics.IKE_CALLER_UNKNOWN, 1446 IkeMetrics.IKE_SESSION_TYPE_CHILD, 1447 IkeMetrics.IKE_STATE_CHILD_REKEY_LOCAL_CREATE, 1448 SaProposal.DH_GROUP_NONE, 1449 IkeMetrics.ENCRYPTION_ALGORITHM_AES_CBC, 1450 IkeMetrics.KEY_LEN_AES_128, 1451 IkeMetrics.INTEGRITY_ALGORITHM_HMAC_SHA1_96, 1452 IkeMetrics.PSEUDORANDOM_FUNCTION_UNSPECIFIED, 1453 IkeMetrics.IKE_ERROR_NONE); 1454 } 1455 1456 @Test testRekeyLocalCreateHandlesDeleteRequest()1457 public void testRekeyLocalCreateHandlesDeleteRequest() throws Exception { 1458 setupStateMachineAndSpiForLocalRekey(); 1459 1460 // Send Rekey-Create request 1461 mChildSessionStateMachine.rekeyChildSession(); 1462 mLooper.dispatchAll(); 1463 1464 // Receive Delete request 1465 mChildSessionStateMachine.receiveRequest( 1466 IKE_EXCHANGE_SUBTYPE_DELETE_CHILD, 1467 EXCHANGE_TYPE_INFORMATIONAL, 1468 makeDeletePayloads(mSpyCurrentChildSaRecord.getRemoteSpi())); 1469 mLooper.dispatchAll(); 1470 1471 // Verify Delete response was sent, users were notified and statemachine is still running 1472 verifyOutboundDeletePayload(mSpyCurrentChildSaRecord.getLocalSpi(), true /*isResp*/); 1473 verifyNotifyUsersDeleteSession( 1474 mSpyUserCbExecutor, mChildSessionStateMachine.mRekeyChildLocalCreate); 1475 assertNotNull(mChildSessionStateMachine.getCurrentState()); 1476 1477 // Receive Rekey Create response and verify Child Session is closed 1478 List<IkePayload> rekeyRespPayloads = receiveRekeyChildResponse(); 1479 assertNull(mChildSessionStateMachine.getCurrentState()); 1480 verifyNoMoreInteractions(mIkeMetrics); 1481 } 1482 1483 @Test testRekeyLocalCreateHandlesRespWithMissingPayload()1484 public void testRekeyLocalCreateHandlesRespWithMissingPayload() throws Exception { 1485 setupIdleStateMachine(); 1486 setUpSpiResource(LOCAL_ADDRESS, LOCAL_INIT_NEW_CHILD_SA_SPI_IN); 1487 reset(mMockChildSessionSmCallback); 1488 1489 // Send Rekey-Create request 1490 mChildSessionStateMachine.rekeyChildSession(); 1491 mLooper.dispatchAll(); 1492 1493 // Receive response with no SA Payload 1494 List<IkePayload> validRekeyRespPayloads = 1495 makeInboundRekeyChildPayloads( 1496 LOCAL_INIT_NEW_CHILD_SA_SPI_OUT, 1497 REKEY_CHILD_RESP_SA_PAYLOAD, 1498 true /*isLocalInitRekey*/); 1499 List<IkePayload> respPayloads = new ArrayList<>(); 1500 for (IkePayload payload : validRekeyRespPayloads) { 1501 if (IkePayload.PAYLOAD_TYPE_SA == payload.payloadType) continue; 1502 respPayloads.add(payload); 1503 } 1504 mChildSessionStateMachine.receiveResponse(EXCHANGE_TYPE_CREATE_CHILD_SA, respPayloads); 1505 mLooper.dispatchAll(); 1506 1507 // Verify user was notified and state machine has quit. 1508 verifyNotifyUsersDeleteSession( 1509 mSpyUserCbExecutor, 1510 mChildSessionStateMachine.mRekeyChildLocalCreate, 1511 InvalidSyntaxException.class, 1512 IkeMetrics.IKE_ERROR_PROTOCOL_INVALID_SYNTAX); 1513 1514 // Verify no SPI for provisional Child was registered. 1515 verify(mMockChildSessionSmCallback, never()) 1516 .onChildSaCreated(anyInt(), eq(mChildSessionStateMachine)); 1517 1518 // Verify retry was not scheduled 1519 verify(mMockChildSessionSmCallback, never()).scheduleRetryLocalRequest(any()); 1520 } 1521 1522 @Ignore disableTestRekeyLocalCreateChildHandlesKeyCalculationFail()1523 public void disableTestRekeyLocalCreateChildHandlesKeyCalculationFail() throws Exception { 1524 // Throw exception when building ChildSaRecord 1525 when(mMockSaRecordHelper.makeChildSaRecord(any(), any(), any())) 1526 .thenThrow( 1527 new GeneralSecurityException( 1528 "testRekeyCreateChildHandlesKeyCalculationFail")); 1529 1530 // Setup for rekey negotiation 1531 setupIdleStateMachine(); 1532 setUpSpiResource(LOCAL_ADDRESS, LOCAL_INIT_NEW_CHILD_SA_SPI_IN); 1533 setUpSpiResource(REMOTE_ADDRESS, LOCAL_INIT_NEW_CHILD_SA_SPI_OUT); 1534 reset(mMockChildSessionSmCallback); 1535 1536 // Send Rekey-Create request 1537 mChildSessionStateMachine.rekeyChildSession(); 1538 mLooper.dispatchAll(); 1539 assertTrue( 1540 mChildSessionStateMachine.getCurrentState() 1541 instanceof ChildSessionStateMachine.RekeyChildLocalCreate); 1542 1543 // Receive Rekey response 1544 List<IkePayload> rekeyRespPayloads = 1545 makeInboundRekeyChildPayloads( 1546 LOCAL_INIT_NEW_CHILD_SA_SPI_OUT, 1547 REKEY_CHILD_RESP_SA_PAYLOAD, 1548 true /*isLocalInitRekey*/); 1549 mChildSessionStateMachine.receiveResponse(EXCHANGE_TYPE_CREATE_CHILD_SA, rekeyRespPayloads); 1550 mLooper.dispatchAll(); 1551 1552 // Verify user was notified and state machine has quit. 1553 verifyNotifyUsersDeleteSession( 1554 mSpyUserCbExecutor, 1555 mChildSessionStateMachine.mRekeyChildLocalCreate, 1556 IkeInternalException.class, 1557 IkeMetrics.IKE_ERROR_INTERNAL); 1558 1559 // Verify SPI for provisional Child was registered and unregistered. 1560 verify(mMockChildSessionSmCallback) 1561 .onChildSaCreated(LOCAL_INIT_NEW_CHILD_SA_SPI_OUT, mChildSessionStateMachine); 1562 verify(mMockChildSessionSmCallback).onChildSaDeleted(LOCAL_INIT_NEW_CHILD_SA_SPI_OUT); 1563 1564 // Verify retry was not scheduled 1565 verify(mMockChildSessionSmCallback, never()).scheduleRetryLocalRequest(any()); 1566 } 1567 1568 @Test testRekeyChildLocalDeleteSendsRequest()1569 public void testRekeyChildLocalDeleteSendsRequest() throws Exception { 1570 setupIdleStateMachine(); 1571 1572 // Seed fake rekey data and force transition to RekeyChildLocalDelete 1573 mChildSessionStateMachine.mLocalInitNewChildSaRecord = mSpyLocalInitNewChildSaRecord; 1574 mChildSessionStateMachine.sendMessage( 1575 CMD_FORCE_TRANSITION, mChildSessionStateMachine.mRekeyChildLocalDelete); 1576 mLooper.dispatchAll(); 1577 1578 // Verify outbound delete request 1579 assertTrue( 1580 mChildSessionStateMachine.getCurrentState() 1581 instanceof ChildSessionStateMachine.RekeyChildLocalDelete); 1582 verifyOutboundDeletePayload(mSpyCurrentChildSaRecord.getLocalSpi(), false /*isResp*/); 1583 1584 assertEquals(mSpyCurrentChildSaRecord, mChildSessionStateMachine.mCurrentChildSaRecord); 1585 assertEquals( 1586 mSpyLocalInitNewChildSaRecord, mChildSessionStateMachine.mChildSaRecordSurviving); 1587 } 1588 verifyChildSaUpdated(ChildSaRecord oldSaRecord, ChildSaRecord newSaRecord)1589 void verifyChildSaUpdated(ChildSaRecord oldSaRecord, ChildSaRecord newSaRecord) { 1590 verify(mMockChildSessionSmCallback).onChildSaDeleted(oldSaRecord.getRemoteSpi()); 1591 verify(oldSaRecord).close(); 1592 1593 assertNull(mChildSessionStateMachine.mChildSaRecordSurviving); 1594 assertEquals(newSaRecord, mChildSessionStateMachine.mCurrentChildSaRecord); 1595 } 1596 mockRekeyChildLocalCreate()1597 private void mockRekeyChildLocalCreate() throws Exception { 1598 setupIdleStateMachine(); 1599 1600 // Seed fake rekey data and force transition to RekeyChildLocalDelete 1601 mChildSessionStateMachine.mLocalInitNewChildSaRecord = mSpyLocalInitNewChildSaRecord; 1602 mChildSessionStateMachine.sendMessage( 1603 CMD_FORCE_TRANSITION, mChildSessionStateMachine.mRekeyChildLocalDelete); 1604 mLooper.dispatchAll(); 1605 } 1606 1607 @Test testRekeyChildLocalDeleteValidatesResponse()1608 public void testRekeyChildLocalDeleteValidatesResponse() throws Exception { 1609 mockRekeyChildLocalCreate(); 1610 1611 // Test receiving Delete response 1612 mChildSessionStateMachine.receiveResponse( 1613 EXCHANGE_TYPE_INFORMATIONAL, 1614 makeDeletePayloads(mSpyCurrentChildSaRecord.getRemoteSpi())); 1615 mLooper.dispatchAll(); 1616 1617 verifyRekeyChildLocalDeleteIsDone(); 1618 } 1619 verifyRekeyChildLocalDeleteIsDone()1620 private void verifyRekeyChildLocalDeleteIsDone() throws Exception { 1621 assertTrue( 1622 mChildSessionStateMachine.getCurrentState() 1623 instanceof ChildSessionStateMachine.Idle); 1624 1625 // First invoked in #setupIdleStateMachine 1626 verify(mMockChildSessionSmCallback, times(2)) 1627 .onProcedureFinished(mChildSessionStateMachine); 1628 1629 verifyChildSaUpdated(mSpyCurrentChildSaRecord, mSpyLocalInitNewChildSaRecord); 1630 1631 verify(mSpyUserCbExecutor).execute(any(Runnable.class)); 1632 verify(mMockChildSessionCallback, never()).onClosed(); 1633 verifyNotifyUserDeleteChildSa(mSpyCurrentChildSaRecord); 1634 } 1635 1636 @Test testRekeyLocalDeleteHandlesRekeyRequest()1637 public void testRekeyLocalDeleteHandlesRekeyRequest() throws Exception { 1638 mockRekeyChildLocalCreate(); 1639 1640 receiveRekeyChildRequest(); 1641 1642 // Verify error notification was sent and state machine stays in the same state 1643 verifyOutboundErrorNotify(EXCHANGE_TYPE_INFORMATIONAL, ERROR_TYPE_TEMPORARY_FAILURE); 1644 assertTrue( 1645 mChildSessionStateMachine.getCurrentState() 1646 instanceof ChildSessionStateMachine.RekeyChildLocalDelete); 1647 1648 // Test receiving Delete response 1649 mChildSessionStateMachine.receiveResponse( 1650 EXCHANGE_TYPE_INFORMATIONAL, 1651 makeDeletePayloads(mSpyCurrentChildSaRecord.getRemoteSpi())); 1652 mLooper.dispatchAll(); 1653 verifyRekeyChildLocalDeleteIsDone(); 1654 } 1655 1656 @Test testRekeyLocalDeleteHandlesDeleteRequest()1657 public void testRekeyLocalDeleteHandlesDeleteRequest() throws Exception { 1658 mockRekeyChildLocalCreate(); 1659 1660 // Test receiving Delete request 1661 mChildSessionStateMachine.receiveRequest( 1662 IKE_EXCHANGE_SUBTYPE_DELETE_CHILD, 1663 EXCHANGE_TYPE_INFORMATIONAL, 1664 makeDeletePayloads(mSpyCurrentChildSaRecord.getRemoteSpi())); 1665 mLooper.dispatchAll(); 1666 1667 // Verify empty message was sent and state machine stays in the same state 1668 verify(mMockChildSessionSmCallback) 1669 .onOutboundPayloadsReady( 1670 eq(EXCHANGE_TYPE_INFORMATIONAL), 1671 eq(true /*isResp*/), 1672 mPayloadListCaptor.capture(), 1673 eq(mChildSessionStateMachine)); 1674 assertTrue(mPayloadListCaptor.getValue().isEmpty()); 1675 assertTrue( 1676 mChildSessionStateMachine.getCurrentState() 1677 instanceof ChildSessionStateMachine.RekeyChildLocalDelete); 1678 1679 // Test receiving Delete response 1680 mChildSessionStateMachine.receiveResponse(EXCHANGE_TYPE_INFORMATIONAL, new ArrayList<>()); 1681 mLooper.dispatchAll(); 1682 verifyRekeyChildLocalDeleteIsDone(); 1683 } 1684 1685 @Test testRekeyChildLocalDeleteHandlesInvalidResp()1686 public void testRekeyChildLocalDeleteHandlesInvalidResp() throws Exception { 1687 setupIdleStateMachine(); 1688 1689 // Seed fake rekey data and force transition to RekeyChildLocalDelete 1690 mChildSessionStateMachine.mLocalInitNewChildSaRecord = mSpyLocalInitNewChildSaRecord; 1691 mChildSessionStateMachine.sendMessage( 1692 CMD_FORCE_TRANSITION, mChildSessionStateMachine.mRekeyChildLocalDelete); 1693 mLooper.dispatchAll(); 1694 1695 // Test receiving Delete response with missing Delete payload 1696 mChildSessionStateMachine.receiveResponse( 1697 EXCHANGE_TYPE_INFORMATIONAL, new ArrayList<IkePayload>()); 1698 mLooper.dispatchAll(); 1699 1700 // Verify rekey has finished 1701 assertTrue( 1702 mChildSessionStateMachine.getCurrentState() 1703 instanceof ChildSessionStateMachine.Idle); 1704 verifyChildSaUpdated(mSpyCurrentChildSaRecord, mSpyLocalInitNewChildSaRecord); 1705 verifyNotifyUserDeleteChildSa(mSpyCurrentChildSaRecord); 1706 1707 // First invoked in #setupIdleStateMachine 1708 verify(mMockChildSessionSmCallback, times(2)) 1709 .onProcedureFinished(mChildSessionStateMachine); 1710 } 1711 1712 @Test testRekeyChildRemoteCreate()1713 public void testRekeyChildRemoteCreate() throws Exception { 1714 setupIdleStateMachine(); 1715 1716 // Setup for new Child SA negotiation. 1717 setUpSpiResource(LOCAL_ADDRESS, REMOTE_INIT_NEW_CHILD_SA_SPI_IN); 1718 setUpSpiResource(REMOTE_ADDRESS, REMOTE_INIT_NEW_CHILD_SA_SPI_OUT); 1719 1720 List<IkePayload> rekeyReqPayloads = receiveRekeyChildRequest(); 1721 1722 assertEquals(0, mChildSessionStateMachine.mSaProposal.getDhGroups().size()); 1723 1724 assertTrue( 1725 mChildSessionStateMachine.getCurrentState() 1726 instanceof ChildSessionStateMachine.RekeyChildRemoteDelete); 1727 1728 // Verify outbound rekey response 1729 verify(mMockChildSessionSmCallback) 1730 .onOutboundPayloadsReady( 1731 eq(EXCHANGE_TYPE_CREATE_CHILD_SA), 1732 eq(true), 1733 mPayloadListCaptor.capture(), 1734 eq(mChildSessionStateMachine)); 1735 List<IkePayload> respPayloadList = mPayloadListCaptor.getValue(); 1736 verifyOutboundCreatePayloadTypes(respPayloadList, true /*isRekey*/); 1737 1738 verifyOutboundRekeySaPayload(respPayloadList, true /*isResp*/); 1739 verifyOutboundRekeyNotifyPayload(respPayloadList); 1740 1741 // Verify new Child SA 1742 assertEquals( 1743 mSpyRemoteInitNewChildSaRecord, 1744 mChildSessionStateMachine.mRemoteInitNewChildSaRecord); 1745 1746 verify(mMockChildSessionSmCallback) 1747 .onChildSaCreated( 1748 eq(mSpyRemoteInitNewChildSaRecord.getRemoteSpi()), 1749 eq(mChildSessionStateMachine)); 1750 1751 verify(mMockSaRecordHelper) 1752 .makeChildSaRecord( 1753 eq(rekeyReqPayloads), 1754 any(List.class), 1755 mChildSaRecordConfigCaptor.capture()); 1756 ChildSaRecordConfig childSaRecordConfig = mChildSaRecordConfigCaptor.getValue(); 1757 verifyChildSaRecordConfig( 1758 childSaRecordConfig, 1759 REMOTE_INIT_NEW_CHILD_SA_SPI_OUT, 1760 REMOTE_INIT_NEW_CHILD_SA_SPI_IN, 1761 false /*isLocalInit*/); 1762 1763 // Verify that users are notified the creation of new inbound IpSecTransform 1764 verify(mSpyUserCbExecutor).execute(any(Runnable.class)); 1765 verifyNotifyUsersCreateIpSecSa(mSpyRemoteInitNewChildSaRecord, true /*expectInbound*/); 1766 verifyIkeSaMetricsLogged( 1767 1, 1768 IkeMetrics.IKE_CALLER_UNKNOWN, 1769 IkeMetrics.IKE_SESSION_TYPE_CHILD, 1770 IkeMetrics.IKE_STATE_CHILD_REKEY_REMOTE_CREATE, 1771 SaProposal.DH_GROUP_NONE, 1772 IkeMetrics.ENCRYPTION_ALGORITHM_AES_CBC, 1773 IkeMetrics.KEY_LEN_AES_128, 1774 IkeMetrics.INTEGRITY_ALGORITHM_HMAC_SHA1_96, 1775 IkeMetrics.PSEUDORANDOM_FUNCTION_UNSPECIFIED, 1776 IkeMetrics.IKE_ERROR_NONE); 1777 } 1778 verifyOutboundErrorNotify(int exchangeType, int errorCode)1779 private void verifyOutboundErrorNotify(int exchangeType, int errorCode) { 1780 verify(mMockChildSessionSmCallback) 1781 .onOutboundPayloadsReady( 1782 eq(exchangeType), 1783 eq(true), 1784 mPayloadListCaptor.capture(), 1785 eq(mChildSessionStateMachine)); 1786 List<IkePayload> respPayloadList = mPayloadListCaptor.getValue(); 1787 1788 assertEquals(1, respPayloadList.size()); 1789 IkePayload payload = respPayloadList.get(0); 1790 assertEquals(IkePayload.PAYLOAD_TYPE_NOTIFY, payload.payloadType); 1791 assertEquals(errorCode, ((IkeNotifyPayload) payload).notifyType); 1792 } 1793 1794 @Test testRekeyChildRemoteCreateHandlesInvalidReq()1795 public void testRekeyChildRemoteCreateHandlesInvalidReq() throws Exception { 1796 setupIdleStateMachine(); 1797 1798 List<IkePayload> rekeyReqPayloads = 1799 makeInboundRekeyChildPayloads( 1800 REMOTE_INIT_NEW_CHILD_SA_SPI_OUT, 1801 REKEY_CHILD_UNACCEPTABLE_REQ_SA_PAYLOAD, 1802 false /*isLocalInitRekey*/); 1803 1804 // Receive rekey Child request 1805 mChildSessionStateMachine.receiveRequest( 1806 IKE_EXCHANGE_SUBTYPE_REKEY_CHILD, EXCHANGE_TYPE_CREATE_CHILD_SA, rekeyReqPayloads); 1807 mLooper.dispatchAll(); 1808 1809 // Verify error notification was sent and state machind was back to Idle 1810 verifyOutboundErrorNotify(EXCHANGE_TYPE_CREATE_CHILD_SA, ERROR_TYPE_NO_PROPOSAL_CHOSEN); 1811 1812 assertTrue( 1813 mChildSessionStateMachine.getCurrentState() 1814 instanceof ChildSessionStateMachine.Idle); 1815 } 1816 1817 @Test testRekeyChildRemoteCreateSaCreationFail()1818 public void testRekeyChildRemoteCreateSaCreationFail() throws Exception { 1819 // Throw exception when building ChildSaRecord 1820 when(mMockSaRecordHelper.makeChildSaRecord(any(), any(), any())) 1821 .thenThrow( 1822 new GeneralSecurityException("testRekeyChildRemoteCreateSaCreationFail")); 1823 1824 setupIdleStateMachine(); 1825 1826 List<IkePayload> rekeyReqPayloads = 1827 makeInboundRekeyChildPayloads( 1828 REMOTE_INIT_NEW_CHILD_SA_SPI_OUT, 1829 REKEY_CHILD_REQ_SA_PAYLOAD, 1830 false /*isLocalInitRekey*/); 1831 1832 // Receive rekey Child request 1833 mChildSessionStateMachine.receiveRequest( 1834 IKE_EXCHANGE_SUBTYPE_REKEY_CHILD, EXCHANGE_TYPE_CREATE_CHILD_SA, rekeyReqPayloads); 1835 mLooper.dispatchAll(); 1836 1837 // Verify error notification was sent and state machind was back to Idle 1838 verifyOutboundErrorNotify(EXCHANGE_TYPE_CREATE_CHILD_SA, ERROR_TYPE_NO_PROPOSAL_CHOSEN); 1839 1840 assertTrue( 1841 mChildSessionStateMachine.getCurrentState() 1842 instanceof ChildSessionStateMachine.Idle); 1843 } 1844 1845 @Test testRekeyChildRemoteDelete()1846 public void testRekeyChildRemoteDelete() throws Exception { 1847 setupIdleStateMachine(); 1848 1849 // Seed fake rekey data and force transition to RekeyChildRemoteDelete 1850 mChildSessionStateMachine.mRemoteInitNewChildSaRecord = mSpyRemoteInitNewChildSaRecord; 1851 mChildSessionStateMachine.sendMessage( 1852 CMD_FORCE_TRANSITION, mChildSessionStateMachine.mRekeyChildRemoteDelete); 1853 1854 // Test receiving Delete request 1855 mChildSessionStateMachine.receiveRequest( 1856 IKE_EXCHANGE_SUBTYPE_DELETE_CHILD, 1857 EXCHANGE_TYPE_INFORMATIONAL, 1858 makeDeletePayloads(mSpyCurrentChildSaRecord.getRemoteSpi())); 1859 mLooper.dispatchAll(); 1860 1861 // Verify outbound Delete response 1862 verifyOutboundDeletePayload(mSpyCurrentChildSaRecord.getLocalSpi(), true /*isResp*/); 1863 1864 // Verify Child SA has been updated 1865 verifyChildSaUpdated(mSpyCurrentChildSaRecord, mSpyRemoteInitNewChildSaRecord); 1866 1867 // Verify procedure has been finished. #onProcedureFinished was first invoked in 1868 // #setupIdleStateMachine 1869 verify(mMockChildSessionSmCallback, times(2)) 1870 .onProcedureFinished(mChildSessionStateMachine); 1871 assertTrue( 1872 mChildSessionStateMachine.getCurrentState() 1873 instanceof ChildSessionStateMachine.Idle); 1874 1875 verify(mSpyUserCbExecutor, times(2)).execute(any(Runnable.class)); 1876 1877 verifyNotifyUserDeleteChildSa(mSpyCurrentChildSaRecord); 1878 verifyNotifyUsersCreateIpSecSa(mSpyRemoteInitNewChildSaRecord, false /*expectInbound*/); 1879 verify(mMockChildSessionCallback, never()).onClosed(); 1880 } 1881 1882 @Test testRekeyChildLocalDeleteWithReqForNewSa()1883 public void testRekeyChildLocalDeleteWithReqForNewSa() throws Exception { 1884 setupIdleStateMachine(); 1885 reset(mMockChildSessionSmCallback); 1886 1887 // Seed fake rekey data and force transition to RekeyChildLocalDelete 1888 mChildSessionStateMachine.mLocalInitNewChildSaRecord = mSpyLocalInitNewChildSaRecord; 1889 mChildSessionStateMachine.sendMessage( 1890 CMD_FORCE_TRANSITION, mChildSessionStateMachine.mRekeyChildLocalDelete); 1891 mLooper.dispatchAll(); 1892 1893 // Test receiving Delete new Child SA request 1894 mChildSessionStateMachine.receiveRequest( 1895 IKE_EXCHANGE_SUBTYPE_DELETE_CHILD, 1896 EXCHANGE_TYPE_INFORMATIONAL, 1897 makeDeletePayloads(mSpyLocalInitNewChildSaRecord.getRemoteSpi())); 1898 1899 // Only dispatch the Message of receiving request 1900 mLooper.dispatchNext(); 1901 assertTrue(mChildSessionStateMachine.getCurrentState() instanceof IdleWithDeferredRequest); 1902 verify(mMockChildSessionSmCallback, never()).onProcedureFinished(mChildSessionStateMachine); 1903 1904 // Continue dispatching the deferred request 1905 mLooper.dispatchAll(); 1906 1907 // Verify outbound Delete response on new Child SA 1908 verifyOutboundDeletePayload(mSpyLocalInitNewChildSaRecord.getLocalSpi(), true /*isResp*/); 1909 verify(mMockChildSessionSmCallback) 1910 .onChildSaDeleted(mSpyLocalInitNewChildSaRecord.getRemoteSpi()); 1911 verify(mSpyLocalInitNewChildSaRecord).close(); 1912 1913 assertNull(mChildSessionStateMachine.getCurrentState()); 1914 1915 verify(mSpyUserCbExecutor, times(2)).execute(any(Runnable.class)); 1916 1917 verifyNotifyUserDeleteChildSa(mSpyCurrentChildSaRecord); 1918 verifyNotifyUserDeleteChildSa(mSpyLocalInitNewChildSaRecord); 1919 1920 verify(mMockChildSessionCallback).onClosed(); 1921 1922 // #onProcedureFinished is only called when Child Session is closed 1923 verify(mMockChildSessionSmCallback).onProcedureFinished(mChildSessionStateMachine); 1924 } 1925 1926 @Test testRekeyChildRemoteDeleteWithReqForNewSa()1927 public void testRekeyChildRemoteDeleteWithReqForNewSa() throws Exception { 1928 setupIdleStateMachine(); 1929 reset(mMockChildSessionSmCallback); 1930 1931 // Seed fake rekey data and force transition to RekeyChildRemoteDelete 1932 mChildSessionStateMachine.mRemoteInitNewChildSaRecord = mSpyRemoteInitNewChildSaRecord; 1933 mChildSessionStateMachine.sendMessage( 1934 CMD_FORCE_TRANSITION, mChildSessionStateMachine.mRekeyChildRemoteDelete); 1935 mLooper.dispatchAll(); 1936 1937 // Test receiving Delete new Child SA request 1938 mChildSessionStateMachine.receiveRequest( 1939 IKE_EXCHANGE_SUBTYPE_DELETE_CHILD, 1940 EXCHANGE_TYPE_INFORMATIONAL, 1941 makeDeletePayloads(mSpyRemoteInitNewChildSaRecord.getRemoteSpi())); 1942 1943 // Only dispatch the Message of receiving request 1944 mLooper.dispatchNext(); 1945 assertTrue(mChildSessionStateMachine.getCurrentState() instanceof IdleWithDeferredRequest); 1946 verify(mMockChildSessionSmCallback, never()).onProcedureFinished(mChildSessionStateMachine); 1947 1948 // Continue dispatching the deferred request 1949 mLooper.dispatchAll(); 1950 1951 // Verify outbound Delete response on new Child SA 1952 verifyOutboundDeletePayload(mSpyRemoteInitNewChildSaRecord.getLocalSpi(), true /*isResp*/); 1953 verify(mMockChildSessionSmCallback) 1954 .onChildSaDeleted(mSpyRemoteInitNewChildSaRecord.getRemoteSpi()); 1955 verify(mSpyRemoteInitNewChildSaRecord).close(); 1956 1957 assertNull(mChildSessionStateMachine.getCurrentState()); 1958 1959 verify(mSpyUserCbExecutor, times(3)).execute(any(Runnable.class)); 1960 1961 verifyNotifyUserDeleteChildSa(mSpyCurrentChildSaRecord); 1962 verifyNotifyUserDeleteChildSa(mSpyRemoteInitNewChildSaRecord); 1963 verifyNotifyUsersCreateIpSecSa(mSpyRemoteInitNewChildSaRecord, false /*expectInbound*/); 1964 1965 verify(mMockChildSessionCallback).onClosed(); 1966 1967 // #onProcedureFinished is only called when Child Session is closed 1968 verify(mMockChildSessionSmCallback).onProcedureFinished(mChildSessionStateMachine); 1969 } 1970 1971 @Test testRekeyChildRemoteDeleteTimeout()1972 public void testRekeyChildRemoteDeleteTimeout() throws Exception { 1973 setupIdleStateMachine(); 1974 1975 // Seed fake rekey data and force transition to RekeyChildRemoteDelete 1976 mChildSessionStateMachine.mRemoteInitNewChildSaRecord = mSpyRemoteInitNewChildSaRecord; 1977 mChildSessionStateMachine.sendMessage( 1978 CMD_FORCE_TRANSITION, mChildSessionStateMachine.mRekeyChildRemoteDelete); 1979 mLooper.dispatchAll(); 1980 1981 mLooper.moveTimeForward(REKEY_DELETE_TIMEOUT_MS); 1982 mLooper.dispatchAll(); 1983 1984 // Verify no response sent. 1985 verify(mMockChildSessionSmCallback, never()) 1986 .onOutboundPayloadsReady(anyInt(), anyBoolean(), any(List.class), any()); 1987 1988 // Verify Child SA has been renewed 1989 verifyChildSaUpdated(mSpyCurrentChildSaRecord, mSpyRemoteInitNewChildSaRecord); 1990 1991 // Verify procedure has been finished. #onProcedureFinished was first invoked in 1992 // #setupIdleStateMachine 1993 verify(mMockChildSessionSmCallback, times(2)) 1994 .onProcedureFinished(mChildSessionStateMachine); 1995 assertTrue( 1996 mChildSessionStateMachine.getCurrentState() 1997 instanceof ChildSessionStateMachine.Idle); 1998 1999 verify(mSpyUserCbExecutor, times(2)).execute(any(Runnable.class)); 2000 2001 verifyNotifyUserDeleteChildSa(mSpyCurrentChildSaRecord); 2002 verifyNotifyUsersCreateIpSecSa(mSpyRemoteInitNewChildSaRecord, false /*expectInbound*/); 2003 2004 verify(mMockChildSessionCallback, never()).onClosed(); 2005 } 2006 2007 @Test testRekeyChildRemoteDeleteExitAndRenter()2008 public void testRekeyChildRemoteDeleteExitAndRenter() throws Exception { 2009 setupIdleStateMachine(); 2010 2011 // Seed fake rekey data and force transition to RekeyChildRemoteDelete 2012 mChildSessionStateMachine.mRemoteInitNewChildSaRecord = mSpyRemoteInitNewChildSaRecord; 2013 mChildSessionStateMachine.sendMessage( 2014 CMD_FORCE_TRANSITION, mChildSessionStateMachine.mRekeyChildRemoteDelete); 2015 mLooper.dispatchAll(); 2016 2017 // Trigger a timeout, and immediately re-enter remote-delete 2018 mLooper.moveTimeForward(REKEY_DELETE_TIMEOUT_MS / 2 + 1); 2019 mChildSessionStateMachine.sendMessage(ChildSessionStateMachine.TIMEOUT_REKEY_REMOTE_DELETE); 2020 mChildSessionStateMachine.sendMessage( 2021 CMD_FORCE_TRANSITION, mChildSessionStateMachine.mRekeyChildRemoteDelete); 2022 mLooper.dispatchAll(); 2023 2024 // Shift time forward 2025 mLooper.moveTimeForward(REKEY_DELETE_TIMEOUT_MS / 2 + 1); 2026 mLooper.dispatchAll(); 2027 2028 // Verify final state has not changed - timeout was not triggered. 2029 assertTrue( 2030 mChildSessionStateMachine.getCurrentState() 2031 instanceof ChildSessionStateMachine.RekeyChildRemoteDelete); 2032 2033 verify(mSpyUserCbExecutor, times(2)).execute(any(Runnable.class)); 2034 2035 verifyNotifyUserDeleteChildSa(mSpyCurrentChildSaRecord); 2036 verifyNotifyUsersCreateIpSecSa(mSpyRemoteInitNewChildSaRecord, false /*expectInbound*/); 2037 2038 verify(mMockChildSessionCallback, never()).onClosed(); 2039 } 2040 2041 @Test testCloseSessionNow()2042 public void testCloseSessionNow() throws Exception { 2043 setupIdleStateMachine(); 2044 2045 // Seed fake rekey data and force transition to RekeyChildLocalDelete 2046 mChildSessionStateMachine.mLocalInitNewChildSaRecord = mSpyLocalInitNewChildSaRecord; 2047 mChildSessionStateMachine.sendMessage( 2048 CMD_FORCE_TRANSITION, mChildSessionStateMachine.mRekeyChildLocalDelete); 2049 2050 mChildSessionStateMachine.killSession(); 2051 mLooper.dispatchAll(); 2052 2053 assertNull(mChildSessionStateMachine.getCurrentState()); 2054 2055 verify(mSpyUserCbExecutor, times(3)).execute(any(Runnable.class)); 2056 2057 verifyNotifyUserDeleteChildSa(mSpyCurrentChildSaRecord); 2058 verifyNotifyUserDeleteChildSa(mSpyLocalInitNewChildSaRecord); 2059 2060 verify(mMockChildSessionCallback).onClosed(); 2061 verify(mIkeMetrics, never()).logSessionTerminated(anyInt(), anyInt(), anyInt(), anyInt()); 2062 } 2063 2064 @Test testValidateExpectKeExistCase()2065 public void testValidateExpectKeExistCase() throws Exception { 2066 doReturn(new DhGroupTransform[] {mChildDhGroupTransform}) 2067 .when(mMockNegotiatedProposal) 2068 .getDhGroupTransforms(); 2069 List<IkePayload> payloadList = new ArrayList<>(); 2070 payloadList.add( 2071 IkeKePayload.createOutboundKePayload( 2072 SaProposal.DH_GROUP_1024_BIT_MODP, createMockRandomFactory())); 2073 2074 CreateChildSaHelper.validateKePayloads( 2075 payloadList, true /*isResp*/, mMockNegotiatedProposal); 2076 CreateChildSaHelper.validateKePayloads( 2077 payloadList, false /*isResp*/, mMockNegotiatedProposal); 2078 } 2079 2080 @Test testValidateExpectNoKeExistCase()2081 public void testValidateExpectNoKeExistCase() throws Exception { 2082 doReturn(new DhGroupTransform[0]).when(mMockNegotiatedProposal).getDhGroupTransforms(); 2083 List<IkePayload> payloadList = new ArrayList<>(); 2084 2085 CreateChildSaHelper.validateKePayloads( 2086 payloadList, true /*isResp*/, mMockNegotiatedProposal); 2087 CreateChildSaHelper.validateKePayloads( 2088 payloadList, false /*isResp*/, mMockNegotiatedProposal); 2089 } 2090 2091 @Test testThrowWhenKeMissing()2092 public void testThrowWhenKeMissing() throws Exception { 2093 doReturn(new DhGroupTransform[] {mChildDhGroupTransform}) 2094 .when(mMockNegotiatedProposal) 2095 .getDhGroupTransforms(); 2096 List<IkePayload> payloadList = new ArrayList<>(); 2097 2098 try { 2099 CreateChildSaHelper.validateKePayloads( 2100 payloadList, true /*isResp*/, mMockNegotiatedProposal); 2101 fail("Expected to fail due to the absence of KE Payload"); 2102 } catch (InvalidSyntaxException expected) { 2103 } 2104 2105 try { 2106 CreateChildSaHelper.validateKePayloads( 2107 payloadList, false /*isResp*/, mMockNegotiatedProposal); 2108 fail("Expected to fail due to the absence of KE Payload"); 2109 } catch (InvalidKeException expected) { 2110 } 2111 } 2112 2113 @Test testThrowWhenKeHasMismatchedDhGroup()2114 public void testThrowWhenKeHasMismatchedDhGroup() throws Exception { 2115 doReturn(new DhGroupTransform[] {mChildDhGroupTransform}) 2116 .when(mMockNegotiatedProposal) 2117 .getDhGroupTransforms(); 2118 List<IkePayload> payloadList = new ArrayList<>(); 2119 payloadList.add( 2120 IkeKePayload.createOutboundKePayload( 2121 SaProposal.DH_GROUP_2048_BIT_MODP, createMockRandomFactory())); 2122 2123 try { 2124 CreateChildSaHelper.validateKePayloads( 2125 payloadList, true /*isResp*/, mMockNegotiatedProposal); 2126 fail("Expected to fail due to mismatched DH Group"); 2127 } catch (InvalidSyntaxException expected) { 2128 } 2129 2130 try { 2131 CreateChildSaHelper.validateKePayloads( 2132 payloadList, false /*isResp*/, mMockNegotiatedProposal); 2133 fail("Expected to fail due to mismatched DH Group"); 2134 } catch (InvalidKeException expected) { 2135 } 2136 } 2137 2138 @Test testThrowForUnexpectedKe()2139 public void testThrowForUnexpectedKe() throws Exception { 2140 DhGroupTransform noneGroup = new DhGroupTransform(SaProposal.DH_GROUP_NONE); 2141 doReturn(new DhGroupTransform[] {noneGroup}) 2142 .when(mMockNegotiatedProposal) 2143 .getDhGroupTransforms(); 2144 List<IkePayload> payloadList = new ArrayList<>(); 2145 payloadList.add( 2146 IkeKePayload.createOutboundKePayload( 2147 SaProposal.DH_GROUP_2048_BIT_MODP, createMockRandomFactory())); 2148 2149 try { 2150 CreateChildSaHelper.validateKePayloads( 2151 payloadList, true /*isResp*/, mMockNegotiatedProposal); 2152 fail("Expected to fail due to unexpected KE payload."); 2153 } catch (InvalidSyntaxException expected) { 2154 } 2155 2156 CreateChildSaHelper.validateKePayloads( 2157 payloadList, false /*isResp*/, mMockNegotiatedProposal); 2158 } 2159 2160 @Test testHandleUnexpectedException()2161 public void testHandleUnexpectedException() throws Exception { 2162 Log spyIkeLog = TestUtils.makeSpyLogDoLogErrorForWtf(TAG); 2163 IkeManager.setIkeLog(spyIkeLog); 2164 2165 mChildSessionStateMachine.createChildSession( 2166 null /*localAddress*/, 2167 REMOTE_ADDRESS, 2168 mMockUdpEncapSocket, 2169 mIkePrf, 2170 IKE_DH_GROUP, 2171 SK_D); 2172 mLooper.dispatchAll(); 2173 2174 verifyHandleFatalErrorAndQuit( 2175 mChildSessionStateMachine.mCreateChildLocalCreate, 2176 IkeInternalException.class, 2177 IkeMetrics.IKE_ERROR_INTERNAL); 2178 verify(spyIkeLog).wtf(anyString(), anyString(), any(RuntimeException.class)); 2179 } 2180 2181 @Test testFirstChildLocalRekey()2182 public void testFirstChildLocalRekey() throws Exception { 2183 ChildSaProposal saProposal = buildSaProposalWithDhGroup(SaProposal.DH_GROUP_2048_BIT_MODP); 2184 ChildSessionParams childSessionParams = 2185 new TunnelModeChildSessionParams.Builder() 2186 .addSaProposal(saProposal) 2187 .addInternalAddressRequest(AF_INET) 2188 .addInternalAddressRequest(INTERNAL_ADDRESS) 2189 .build(); 2190 mChildSessionStateMachine = buildChildSession(childSessionParams); 2191 mChildSessionStateMachine.mIsFirstChild = true; 2192 mChildSessionStateMachine.setDbg(true); 2193 mChildSessionStateMachine.start(); 2194 2195 setupIdleStateMachine(); 2196 2197 assertEquals(0, mChildSessionStateMachine.mSaProposal.getDhGroups().size()); 2198 2199 // Send Rekey-Create request 2200 mChildSessionStateMachine.rekeyChildSession(); 2201 mLooper.dispatchAll(); 2202 2203 assertTrue( 2204 mChildSessionStateMachine.getCurrentState() 2205 instanceof ChildSessionStateMachine.RekeyChildLocalCreate); 2206 2207 verifyOutboundRekeyKePayload(false /*isResp*/); 2208 } 2209 verifyOutboundRekeyKePayload(boolean isResp)2210 private void verifyOutboundRekeyKePayload(boolean isResp) { 2211 verify(mMockChildSessionSmCallback) 2212 .onOutboundPayloadsReady( 2213 eq(EXCHANGE_TYPE_CREATE_CHILD_SA), 2214 eq(isResp), 2215 mPayloadListCaptor.capture(), 2216 eq(mChildSessionStateMachine)); 2217 2218 // Verify outbound payload list 2219 List<IkePayload> reqPayloadList = mPayloadListCaptor.getValue(); 2220 2221 assertNotNull( 2222 IkePayload.getPayloadForTypeInProvidedList( 2223 PAYLOAD_TYPE_KE, IkeKePayload.class, reqPayloadList)); 2224 } 2225 buildChildSession( ChildSessionParams childSessionParams, Executor executor)2226 private ChildSessionStateMachine buildChildSession( 2227 ChildSessionParams childSessionParams, Executor executor) { 2228 return new ChildSessionStateMachine( 2229 new IkeContext(mLooper.getLooper(), mContext, createMockRandomFactory()), 2230 new ChildSessionStateMachine.Config( 2231 IKE_SESSION_UNIQUE_ID, 2232 mMockIkeHandler, 2233 childSessionParams, 2234 mMockIpSecManager, 2235 mIpSecSpiGenerator, 2236 executor), 2237 mMockChildSessionCallback, 2238 mMockChildSessionSmCallback); 2239 } 2240 buildChildSession(ChildSessionParams childSessionParams)2241 private ChildSessionStateMachine buildChildSession(ChildSessionParams childSessionParams) { 2242 return buildChildSession(childSessionParams, mSpyUserCbExecutor); 2243 } 2244 buildChildSession(Executor executor)2245 private ChildSessionStateMachine buildChildSession(Executor executor) { 2246 return buildChildSession(mChildSessionParams, executor); 2247 } 2248 buildAndStartChildSession(Executor executor)2249 private ChildSessionStateMachine buildAndStartChildSession(Executor executor) { 2250 ChildSessionStateMachine childSession = buildChildSession(executor); 2251 childSession.setDbg(true); 2252 childSession.start(); 2253 mLooper.dispatchAll(); 2254 2255 return childSession; 2256 } 2257 buildAndStartStateMachineWithProposal( ChildSaProposal childProposal)2258 private ChildSessionStateMachine buildAndStartStateMachineWithProposal( 2259 ChildSaProposal childProposal) { 2260 ChildSessionParams childSessionParams = 2261 new TunnelModeChildSessionParams.Builder() 2262 .addSaProposal(childProposal) 2263 .addInternalAddressRequest(AF_INET) 2264 .addInternalAddressRequest(INTERNAL_ADDRESS) 2265 .build(); 2266 ChildSessionStateMachine childSession = buildChildSession(childSessionParams); 2267 childSession.setDbg(true); 2268 childSession.start(); 2269 return childSession; 2270 } 2271 buildSaProposalWithDhGroup(int dhGroup)2272 private ChildSaProposal buildSaProposalWithDhGroup(int dhGroup) { 2273 return new ChildSaProposal.Builder() 2274 .addEncryptionAlgorithm( 2275 SaProposal.ENCRYPTION_ALGORITHM_AES_CBC, SaProposal.KEY_LEN_AES_128) 2276 .addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96) 2277 .addDhGroup(dhGroup) 2278 .build(); 2279 } 2280 verifyRemoteRekeyWithKePayload(ChildSaProposal requestSaProposal, int expectedDh)2281 private void verifyRemoteRekeyWithKePayload(ChildSaProposal requestSaProposal, int expectedDh) 2282 throws Exception { 2283 // Setup for new Child SA negotiation. 2284 setUpSpiResource(LOCAL_ADDRESS, REMOTE_INIT_NEW_CHILD_SA_SPI_IN); 2285 setUpSpiResource(REMOTE_ADDRESS, REMOTE_INIT_NEW_CHILD_SA_SPI_OUT); 2286 2287 IkeSaPayload saPayload = 2288 IkeSaPayload.createChildSaRequestPayload( 2289 new ChildSaProposal[] {requestSaProposal}, 2290 mIpSecSpiGenerator, 2291 LOCAL_ADDRESS); 2292 List<IkePayload> rekeyReqPayloads = 2293 makeInboundRekeyChildPayloads( 2294 REMOTE_INIT_NEW_CHILD_SA_SPI_OUT, saPayload, false /*isLocalInitRekey*/); 2295 2296 rekeyReqPayloads.add( 2297 IkeKePayload.createOutboundKePayload(expectedDh, createMockRandomFactory())); 2298 2299 when(mMockSaRecordHelper.makeChildSaRecord( 2300 eq(rekeyReqPayloads), any(List.class), any(ChildSaRecordConfig.class))) 2301 .thenReturn(mSpyRemoteInitNewChildSaRecord); 2302 2303 // Receive rekey Child request 2304 mChildSessionStateMachine.receiveRequest( 2305 IKE_EXCHANGE_SUBTYPE_REKEY_CHILD, EXCHANGE_TYPE_CREATE_CHILD_SA, rekeyReqPayloads); 2306 mLooper.dispatchAll(); 2307 2308 assertTrue( 2309 mChildSessionStateMachine.getCurrentState() 2310 instanceof ChildSessionStateMachine.RekeyChildRemoteDelete); 2311 2312 verifyOutboundRekeyKePayload(true /*isResp*/); 2313 2314 assertEquals(expectedDh, (int) mChildSessionStateMachine.mSaProposal.getDhGroups().get(0)); 2315 } 2316 2317 @Test testRemoteRekeyWithUserSpecifiedKePayload()2318 public void testRemoteRekeyWithUserSpecifiedKePayload() throws Exception { 2319 // Use child session params with dh group to initiate the state machine 2320 ChildSaProposal saProposal = buildSaProposalWithDhGroup(SaProposal.DH_GROUP_2048_BIT_MODP); 2321 mChildSessionStateMachine.quitNow(); 2322 mChildSessionStateMachine = buildAndStartStateMachineWithProposal(saProposal); 2323 2324 setupIdleStateMachine(); 2325 assertEquals(0, mChildSessionStateMachine.mSaProposal.getDhGroups().size()); 2326 2327 verifyRemoteRekeyWithKePayload(saProposal, SaProposal.DH_GROUP_2048_BIT_MODP); 2328 } 2329 2330 @Test testRemoteRekeyWithIkeNegotiatedKePayload()2331 public void testRemoteRekeyWithIkeNegotiatedKePayload() throws Exception { 2332 setupIdleStateMachine(); 2333 2334 assertEquals(0, mChildSessionStateMachine.mSaProposal.getDhGroups().size()); 2335 assertEquals(IKE_DH_GROUP, mChildSessionStateMachine.mIkeDhGroup); 2336 for (SaProposal userProposal : 2337 mChildSessionStateMachine.mChildSessionParams.getChildSaProposals()) { 2338 assertTrue(userProposal.getDhGroups().isEmpty()); 2339 } 2340 2341 ChildSaProposal saProposal = buildSaProposalWithDhGroup(IKE_DH_GROUP); 2342 verifyRemoteRekeyWithKePayload(saProposal, IKE_DH_GROUP); 2343 } 2344 verifyRcvRekeyReqAndRejectWithErrorNotify( List<IkePayload> rekeyReqPayloads, int expectedErrorType)2345 private void verifyRcvRekeyReqAndRejectWithErrorNotify( 2346 List<IkePayload> rekeyReqPayloads, int expectedErrorType) { 2347 mChildSessionStateMachine.receiveRequest( 2348 IKE_EXCHANGE_SUBTYPE_REKEY_CHILD, EXCHANGE_TYPE_CREATE_CHILD_SA, rekeyReqPayloads); 2349 mLooper.dispatchAll(); 2350 2351 assertTrue( 2352 mChildSessionStateMachine.getCurrentState() 2353 instanceof ChildSessionStateMachine.Idle); 2354 2355 verifyOutboundErrorNotify(EXCHANGE_TYPE_CREATE_CHILD_SA, expectedErrorType); 2356 } 2357 2358 @Test testRemoteRekeyWithInvalidKePayload()2359 public void testRemoteRekeyWithInvalidKePayload() throws Exception { 2360 setupIdleStateMachine(); 2361 2362 assertEquals(0, mChildSessionStateMachine.mSaProposal.getDhGroups().size()); 2363 assertEquals(IKE_DH_GROUP, mChildSessionStateMachine.mIkeDhGroup); 2364 for (SaProposal userProposal : 2365 mChildSessionStateMachine.mChildSessionParams.getChildSaProposals()) { 2366 assertTrue(userProposal.getDhGroups().isEmpty()); 2367 } 2368 2369 // Build an inbound Rekey Child request 2370 // Build an SA Payload that includes a Proposal with IKE_DH_GROUP 2371 IkeSaPayload saPayload = 2372 IkeSaPayload.createChildSaRequestPayload( 2373 new ChildSaProposal[] {buildSaProposalWithDhGroup(IKE_DH_GROUP)}, 2374 mIpSecSpiGenerator, 2375 LOCAL_ADDRESS); 2376 List<IkePayload> rekeyReqPayloads = 2377 makeInboundRekeyChildPayloads( 2378 REMOTE_INIT_NEW_CHILD_SA_SPI_OUT, saPayload, false /*isLocalInitRekey*/); 2379 2380 // Build a KE Payload that uses a different DH group from the IKE_DH_GROUP 2381 rekeyReqPayloads.add( 2382 IkeKePayload.createOutboundKePayload( 2383 DH_GROUP_2048_BIT_MODP, createMockRandomFactory())); 2384 2385 verifyRcvRekeyReqAndRejectWithErrorNotify(rekeyReqPayloads, ERROR_TYPE_INVALID_KE_PAYLOAD); 2386 } 2387 2388 @Test testRejectRemoteRekeyWithoutDhGroupInProposal()2389 public void testRejectRemoteRekeyWithoutDhGroupInProposal() throws Exception { 2390 // Use child session params with dh group to initiate the state machine 2391 mChildSessionStateMachine.quitNow(); 2392 ChildSaProposal saProposal = buildSaProposalWithDhGroup(SaProposal.DH_GROUP_2048_BIT_MODP); 2393 mChildSessionStateMachine = buildAndStartStateMachineWithProposal(saProposal); 2394 2395 setupIdleStateMachine(); 2396 mChildSessionStateMachine.mSaProposal = saProposal; 2397 2398 // Build a Rekey request that does not propose DH groups. 2399 IkeSaPayload saPayload = 2400 IkeSaPayload.createChildSaRequestPayload( 2401 new ChildSaProposal[] {buildSaProposal()}, // Proposal with no DH group 2402 mIpSecSpiGenerator, 2403 LOCAL_ADDRESS); 2404 List<IkePayload> rekeyReqPayloads = 2405 makeInboundRekeyChildPayloads( 2406 REMOTE_INIT_NEW_CHILD_SA_SPI_OUT, saPayload, false /* isLocalInitRekey */); 2407 rekeyReqPayloads.add( 2408 IkeKePayload.createOutboundKePayload( 2409 DH_GROUP_2048_BIT_MODP, createMockRandomFactory())); 2410 2411 verifyRcvRekeyReqAndRejectWithErrorNotify(rekeyReqPayloads, ERROR_TYPE_NO_PROPOSAL_CHOSEN); 2412 } 2413 2414 @Test testRejectRemoteRekeyWithoutKePayload()2415 public void testRejectRemoteRekeyWithoutKePayload() throws Exception { 2416 // Use child session params with dh group to initiate the state machine 2417 mChildSessionStateMachine.quitNow(); 2418 ChildSaProposal saProposal = buildSaProposalWithDhGroup(SaProposal.DH_GROUP_2048_BIT_MODP); 2419 mChildSessionStateMachine = buildAndStartStateMachineWithProposal(saProposal); 2420 2421 setupIdleStateMachine(); 2422 mChildSessionStateMachine.mSaProposal = saProposal; 2423 2424 // Build a Rekey request that proposes DH groups but does not include a KE payload 2425 IkeSaPayload saPayload = 2426 IkeSaPayload.createChildSaRequestPayload( 2427 new ChildSaProposal[] {saProposal}, mIpSecSpiGenerator, LOCAL_ADDRESS); 2428 List<IkePayload> rekeyReqPayloads = 2429 makeInboundRekeyChildPayloads( 2430 REMOTE_INIT_NEW_CHILD_SA_SPI_OUT, saPayload, false /* isLocalInitRekey */); 2431 2432 verifyRcvRekeyReqAndRejectWithErrorNotify(rekeyReqPayloads, ERROR_TYPE_INVALID_SYNTAX); 2433 } 2434 verifyMobikeRekeyFallback(UdpEncapsulationSocket newEncapSocket)2435 private void verifyMobikeRekeyFallback(UdpEncapsulationSocket newEncapSocket) throws Exception { 2436 mLooper.dispatchAll(); 2437 2438 verifyRekeyChildLocalCreateHandlesResponse( 2439 ChildSessionStateMachine.MobikeRekeyChildLocalCreate.class, 2440 true /* isMobikeRekey */, 2441 UPDATED_LOCAL_ADDRESS, 2442 REMOTE_ADDRESS, 2443 newEncapSocket); 2444 2445 assertEquals(UPDATED_LOCAL_ADDRESS, mChildSessionStateMachine.mLocalAddress); 2446 assertEquals(REMOTE_ADDRESS, mChildSessionStateMachine.mRemoteAddress); 2447 assertEquals(newEncapSocket, mChildSessionStateMachine.mUdpEncapSocket); 2448 } 2449 2450 @Test testMobikeRekeyChildLocalCreateHandlesResp()2451 public void testMobikeRekeyChildLocalCreateHandlesResp() throws Exception { 2452 setupStateMachineAndSpiForLocalRekey(UPDATED_LOCAL_ADDRESS, REMOTE_ADDRESS); 2453 2454 // Send MOBIKE Rekey-Create request 2455 mChildSessionStateMachine.performRekeyMigration( 2456 UPDATED_LOCAL_ADDRESS, REMOTE_ADDRESS, mMockUdpEncapSocket); 2457 verifyMobikeRekeyFallback(mMockUdpEncapSocket); 2458 } 2459 2460 @Test testMobikeRekeyChildExecuteCbAfterKillSession()2461 public void testMobikeRekeyChildExecuteCbAfterKillSession() throws Exception { 2462 mChildSessionStateMachine.quitNow(); 2463 mLooper.dispatchAll(); 2464 2465 LateExecuteExecutor lateExecutor = spy(new LateExecuteExecutor()); 2466 mChildSessionStateMachine = buildAndStartChildSession(lateExecutor); 2467 2468 setupStateMachineAndSpiForLocalRekey(UPDATED_LOCAL_ADDRESS, REMOTE_ADDRESS); 2469 2470 // MOBIKE Rekey 2471 mChildSessionStateMachine.performRekeyMigration( 2472 UPDATED_LOCAL_ADDRESS, REMOTE_ADDRESS, mMockUdpEncapSocket); 2473 mLooper.dispatchAll(); 2474 receiveRekeyChildResponse(); 2475 mLooper.dispatchAll(); 2476 2477 mChildSessionStateMachine.killSession(); 2478 mLooper.dispatchAll(); 2479 2480 lateExecutor.actuallyExecute(); 2481 verify(mMockChildSessionCallback) 2482 .onIpSecTransformsMigrated( 2483 mSpyLocalInitNewChildSaRecord.getInboundIpSecTransform(), 2484 mSpyLocalInitNewChildSaRecord.getOutboundIpSecTransform()); 2485 } 2486 2487 @Test 2488 @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) testMobike_usesKernelMobikeForSameAddressFamilyAndEncapSocket()2489 public void testMobike_usesKernelMobikeForSameAddressFamilyAndEncapSocket() throws Exception { 2490 verifyMobike_usesKernelMobikeForSameEncapSocket(UPDATED_LOCAL_ADDRESS, REMOTE_ADDRESS); 2491 } 2492 2493 @Test 2494 @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) testMobike_usesKernelMobikeForDifferentAddressFamilyAndSameEncapSocket()2495 public void testMobike_usesKernelMobikeForDifferentAddressFamilyAndSameEncapSocket() 2496 throws Exception { 2497 verifyMobike_usesKernelMobikeForSameEncapSocket(LOCAL_ADDRESS_6, REMOTE_ADDRESS_6); 2498 } 2499 verifyMobike_usesKernelMobikeForSameEncapSocket( InetAddress newLocalAddress, InetAddress newRemoteAddress)2500 private void verifyMobike_usesKernelMobikeForSameEncapSocket( 2501 InetAddress newLocalAddress, InetAddress newRemoteAddress) throws Exception { 2502 doReturn(true) 2503 .when(mMockPackageManager) 2504 .hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNEL_MIGRATION); 2505 setupIdleStateMachine(); 2506 2507 // Send MOBIKE request 2508 mChildSessionStateMachine.performMigration( 2509 newLocalAddress, newRemoteAddress, mMockUdpEncapSocket); 2510 mLooper.dispatchAll(); 2511 2512 // Verify kernel MOBIKE methods called 2513 verify(mMockIpSecService) 2514 .migrateTransform( 2515 anyInt(), 2516 eq(newLocalAddress.getHostAddress()), 2517 eq(newRemoteAddress.getHostAddress()), 2518 any()); 2519 verify(mMockIpSecService) 2520 .migrateTransform( 2521 anyInt(), 2522 eq(newRemoteAddress.getHostAddress()), 2523 eq(newLocalAddress.getHostAddress()), 2524 any()); 2525 2526 // Verify callbacks called, and state machine goes back to Idle state 2527 verify(mMockChildSessionCallback) 2528 .onIpSecTransformsMigrated( 2529 mSpyCurrentChildSaRecord.getInboundIpSecTransform(), 2530 mSpyCurrentChildSaRecord.getOutboundIpSecTransform()); 2531 assertTrue( 2532 mChildSessionStateMachine.getCurrentState() 2533 instanceof ChildSessionStateMachine.Idle); 2534 2535 // Verify addresses and sockets correct 2536 assertEquals(newLocalAddress, mChildSessionStateMachine.mLocalAddress); 2537 assertEquals(newRemoteAddress, mChildSessionStateMachine.mRemoteAddress); 2538 assertEquals(mMockUdpEncapSocket, mChildSessionStateMachine.mUdpEncapSocket); 2539 } 2540 verifyKernelMobikeFallbackForUnsupportedMigrations( UdpEncapsulationSocket newEncapSocket)2541 private void verifyKernelMobikeFallbackForUnsupportedMigrations( 2542 UdpEncapsulationSocket newEncapSocket) throws Exception { 2543 doReturn(true) 2544 .when(mMockPackageManager) 2545 .hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNEL_MIGRATION); 2546 setupStateMachineAndSpiForLocalRekey(UPDATED_LOCAL_ADDRESS, REMOTE_ADDRESS); 2547 2548 // Send MOBIKE request 2549 mChildSessionStateMachine.performMigration( 2550 UPDATED_LOCAL_ADDRESS, REMOTE_ADDRESS, newEncapSocket); 2551 verifyMobikeRekeyFallback(newEncapSocket); 2552 } 2553 2554 @Test 2555 @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) testMobike_usesRekeyMobikeFallbackForChangingEncapSocket()2556 public void testMobike_usesRekeyMobikeFallbackForChangingEncapSocket() throws Exception { 2557 verifyKernelMobikeFallbackForUnsupportedMigrations(mock(UdpEncapsulationSocket.class)); 2558 } 2559 2560 @Test 2561 @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) testMobike_usesRekeyMobikeFallbackForChangingEncapType()2562 public void testMobike_usesRekeyMobikeFallbackForChangingEncapType() throws Exception { 2563 verifyKernelMobikeFallbackForUnsupportedMigrations(null); 2564 } 2565 2566 // TODO (b/277668745): Add tests for 6 -> 4 and 6 -> 6 migrations with and without UDP encap. 2567 2568 private static class LateExecuteExecutor implements Executor { 2569 private final List<Runnable> mCommands = new ArrayList<>(); 2570 2571 @Override execute(Runnable command)2572 public void execute(Runnable command) { 2573 mCommands.add(command); 2574 } 2575 actuallyExecute()2576 public void actuallyExecute() { 2577 for (Runnable c : mCommands) { 2578 c.run(); 2579 } 2580 } 2581 } 2582 } 2583