From 13f043a8db409b38981befb7aab17f62277ae6fe Mon Sep 17 00:00:00 2001 From: evitayan Date: Sun, 10 May 2020 21:58:24 -0700 Subject: [PATCH] Move common logic in testing and verification to IkeSessionTestBase This commit moves following logics to IkeSessionTestBase so that all subclasses can share it: - build ChildParams - perform IKE and first Child setup - perform deleting IKE - verifying IKE and first Child setup Bug: 155821007 Test: atest CtsIkeTestCases:IkeSessionDigitalSignatureTest Change-Id: Ib35b18240396a7b4823111e37be9a338d8ff6f06 --- .../net/ipsec/ike/cts/IkeSessionPskTest.java | 125 ++++-------------- .../net/ipsec/ike/cts/IkeSessionTestBase.java | 93 ++++++++++++- .../net/ipsec/ike/cts/IkeTunUtils.java | 69 +++++----- 3 files changed, 153 insertions(+), 134 deletions(-) diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java index ca7ee1fe49..661457ff5e 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java @@ -16,25 +16,17 @@ package android.net.ipsec.ike.cts; -import static android.net.ipsec.ike.IkeSessionConfiguration.EXTENSION_TYPE_FRAGMENTATION; import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_NO_PROPOSAL_CHOSEN; -import static android.system.OsConstants.AF_INET; -import static android.system.OsConstants.AF_INET6; - -import static com.android.internal.util.HexDump.hexStringToByteArray; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; -import android.net.ipsec.ike.ChildSessionConfiguration; +import android.net.LinkAddress; import android.net.ipsec.ike.IkeFqdnIdentification; import android.net.ipsec.ike.IkeSession; -import android.net.ipsec.ike.IkeSessionConfiguration; -import android.net.ipsec.ike.IkeSessionConnectionInfo; import android.net.ipsec.ike.IkeSessionParams; -import android.net.ipsec.ike.TunnelModeChildSessionParams; import android.net.ipsec.ike.exceptions.IkeException; import android.net.ipsec.ike.exceptions.IkeProtocolException; import android.platform.test.annotations.AppModeFull; @@ -45,10 +37,11 @@ import org.junit.Test; import org.junit.runner.RunWith; import java.net.InetAddress; +import java.util.ArrayList; import java.util.Arrays; @RunWith(AndroidJUnit4.class) -@AppModeFull(reason = "MANAGE_TEST_NETWORKS permission can't be granted to instant apps") +@AppModeFull(reason = "MANAGE_IPSEC_TUNNELS permission can't be granted to instant apps") public class IkeSessionPskTest extends IkeSessionTestBase { // Test vectors for success workflow private static final String SUCCESS_IKE_INIT_RESP = @@ -89,16 +82,6 @@ public class IkeSessionPskTest extends IkeSessionTestBase { + "9352D71100777B00ABCC6BD7DBEA697827FFAAA48DF9A54D1D68161939F5DC8" + "6743A7CEB2BE34AC00095A5B8"; - private static final long IKE_INIT_SPI = Long.parseLong("46B8ECA1E0D72A18", 16); - - private static final TunnelModeChildSessionParams CHILD_PARAMS = - new TunnelModeChildSessionParams.Builder() - .addSaProposal(SaProposalTest.buildChildSaProposalWithNormalModeCipher()) - .addSaProposal(SaProposalTest.buildChildSaProposalWithCombinedModeCipher()) - .addInternalAddressRequest(AF_INET) - .addInternalAddressRequest(AF_INET6) - .build(); - private IkeSession openIkeSessionWithRemoteAddress(InetAddress remoteAddress) { IkeSessionParams ikeParams = new IkeSessionParams.Builder(sContext) @@ -113,7 +96,7 @@ public class IkeSessionPskTest extends IkeSessionTestBase { return new IkeSession( sContext, ikeParams, - CHILD_PARAMS, + buildTunnelModeChildSessionParams(), mUserCbExecutor, mIkeSessionCallback, mFirstChildSessionCallback); @@ -125,45 +108,17 @@ public class IkeSessionPskTest extends IkeSessionTestBase { // Open IKE Session IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); - int expectedMsgId = 0; - mTunUtils.awaitReqAndInjectResp( - IKE_INIT_SPI, - expectedMsgId++, - false /* expectedUseEncap */, - hexStringToByteArray(SUCCESS_IKE_INIT_RESP)); + performSetupIkeAndFirstChildBlocking(SUCCESS_IKE_INIT_RESP, SUCCESS_IKE_AUTH_RESP); - mTunUtils.awaitReqAndInjectResp( - IKE_INIT_SPI, - expectedMsgId++, - true /* expectedUseEncap */, - hexStringToByteArray(SUCCESS_IKE_AUTH_RESP)); + // IKE INIT and IKE AUTH takes two exchanges. Message ID starts from 2 + int expectedMsgId = 2; - // Verify opening IKE Session - IkeSessionConfiguration ikeConfig = mIkeSessionCallback.awaitIkeConfig(); - assertNotNull(ikeConfig); - assertEquals(EXPECTED_REMOTE_APP_VERSION_EMPTY, ikeConfig.getRemoteApplicationVersion()); - assertTrue(ikeConfig.getRemoteVendorIds().isEmpty()); - assertTrue(ikeConfig.getPcscfServers().isEmpty()); - assertTrue(ikeConfig.isIkeExtensionEnabled(EXTENSION_TYPE_FRAGMENTATION)); - - IkeSessionConnectionInfo ikeConnectInfo = ikeConfig.getIkeSessionConnectionInfo(); - assertNotNull(ikeConnectInfo); - assertEquals(mLocalAddress, ikeConnectInfo.getLocalAddress()); - assertEquals(mRemoteAddress, ikeConnectInfo.getRemoteAddress()); - assertEquals(mTunNetwork, ikeConnectInfo.getNetwork()); - - // Verify opening first Child Session - ChildSessionConfiguration firstChildConfig = mFirstChildSessionCallback.awaitChildConfig(); - assertNotNull(firstChildConfig); - assertEquals( - Arrays.asList(EXPECTED_INBOUND_TS), firstChildConfig.getInboundTrafficSelectors()); - assertEquals(Arrays.asList(DEFAULT_V4_TS), firstChildConfig.getOutboundTrafficSelectors()); - assertEquals( - Arrays.asList(EXPECTED_INTERNAL_LINK_ADDR), - firstChildConfig.getInternalAddresses()); - assertTrue(firstChildConfig.getInternalSubnets().isEmpty()); - assertTrue(firstChildConfig.getInternalDnsServers().isEmpty()); - assertTrue(firstChildConfig.getInternalDhcpServers().isEmpty()); + verifyIkeSessionSetupBlocking(); + verifyChildSessionSetupBlocking( + mFirstChildSessionCallback, + Arrays.asList(TUNNEL_MODE_INBOUND_TS), + Arrays.asList(TUNNEL_MODE_OUTBOUND_TS), + Arrays.asList(EXPECTED_INTERNAL_LINK_ADDR)); IpSecTransformCallRecord firstTransformRecordA = mFirstChildSessionCallback.awaitNextCreatedIpSecTransform(); @@ -173,24 +128,19 @@ public class IkeSessionPskTest extends IkeSessionTestBase { // Open additional Child Session TestChildSessionCallback additionalChildCb = new TestChildSessionCallback(); - ikeSession.openChildSession(CHILD_PARAMS, additionalChildCb); + ikeSession.openChildSession(buildTunnelModeChildSessionParams(), additionalChildCb); mTunUtils.awaitReqAndInjectResp( - IKE_INIT_SPI, + IKE_DETERMINISTIC_INITIATOR_SPI, expectedMsgId++, true /* expectedUseEncap */, - hexStringToByteArray(SUCCESS_CREATE_CHILD_RESP)); + SUCCESS_CREATE_CHILD_RESP); // Verify opening additional Child Session - ChildSessionConfiguration additionalChildConfig = additionalChildCb.awaitChildConfig(); - assertNotNull(additionalChildConfig); - assertEquals( - Arrays.asList(EXPECTED_INBOUND_TS), firstChildConfig.getInboundTrafficSelectors()); - assertEquals(Arrays.asList(DEFAULT_V4_TS), firstChildConfig.getOutboundTrafficSelectors()); - assertTrue(additionalChildConfig.getInternalAddresses().isEmpty()); - assertTrue(additionalChildConfig.getInternalSubnets().isEmpty()); - assertTrue(additionalChildConfig.getInternalDnsServers().isEmpty()); - assertTrue(additionalChildConfig.getInternalDhcpServers().isEmpty()); - + verifyChildSessionSetupBlocking( + additionalChildCb, + Arrays.asList(TUNNEL_MODE_INBOUND_TS), + Arrays.asList(TUNNEL_MODE_OUTBOUND_TS), + new ArrayList()); IpSecTransformCallRecord additionalTransformRecordA = additionalChildCb.awaitNextCreatedIpSecTransform(); IpSecTransformCallRecord additionalTransformRecordB = @@ -200,10 +150,10 @@ public class IkeSessionPskTest extends IkeSessionTestBase { // Close additional Child Session ikeSession.closeChildSession(additionalChildCb); mTunUtils.awaitReqAndInjectResp( - IKE_INIT_SPI, + IKE_DETERMINISTIC_INITIATOR_SPI, expectedMsgId++, true /* expectedUseEncap */, - hexStringToByteArray(SUCCESS_DELETE_CHILD_RESP)); + SUCCESS_DELETE_CHILD_RESP); verifyDeleteIpSecTransformPair( additionalChildCb, additionalTransformRecordA, additionalTransformRecordB); @@ -211,16 +161,8 @@ public class IkeSessionPskTest extends IkeSessionTestBase { // Close IKE Session ikeSession.close(); - mTunUtils.awaitReqAndInjectResp( - IKE_INIT_SPI, - expectedMsgId++, - true /* expectedUseEncap */, - hexStringToByteArray(SUCCESS_DELETE_IKE_RESP)); - - verifyDeleteIpSecTransformPair( - mFirstChildSessionCallback, firstTransformRecordA, firstTransformRecordB); - mFirstChildSessionCallback.awaitOnClosed(); - mIkeSessionCallback.awaitOnClosed(); + performCloseIkeBlocking(expectedMsgId++, SUCCESS_DELETE_IKE_RESP); + verifyCloseIkeAndChildBlocking(firstTransformRecordA, firstTransformRecordB); } @Test @@ -229,18 +171,7 @@ public class IkeSessionPskTest extends IkeSessionTestBase { // Open IKE Session IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); - int expectedMsgId = 0; - mTunUtils.awaitReqAndInjectResp( - IKE_INIT_SPI, - expectedMsgId++, - false /* expectedUseEncap */, - hexStringToByteArray(SUCCESS_IKE_INIT_RESP)); - - mTunUtils.awaitReqAndInjectResp( - IKE_INIT_SPI, - expectedMsgId++, - true /* expectedUseEncap */, - hexStringToByteArray(SUCCESS_IKE_AUTH_RESP)); + performSetupIkeAndFirstChildBlocking(SUCCESS_IKE_INIT_RESP, SUCCESS_IKE_AUTH_RESP); ikeSession.kill(); mFirstChildSessionCallback.awaitOnClosed(); @@ -256,10 +187,10 @@ public class IkeSessionPskTest extends IkeSessionTestBase { IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress); int expectedMsgId = 0; mTunUtils.awaitReqAndInjectResp( - IKE_INIT_SPI, + IKE_DETERMINISTIC_INITIATOR_SPI, expectedMsgId++, false /* expectedUseEncap */, - hexStringToByteArray(ikeInitFailRespHex)); + ikeInitFailRespHex); mFirstChildSessionCallback.awaitOnClosed(); diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java index e49f75fabb..ade9813a81 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java @@ -16,9 +16,13 @@ package android.net.ipsec.ike.cts; import static android.app.AppOpsManager.OP_MANAGE_IPSEC_TUNNELS; +import static android.net.ipsec.ike.IkeSessionConfiguration.EXTENSION_TYPE_FRAGMENTATION; +import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.AF_INET6; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import android.annotation.NonNull; import android.app.AppOpsManager; @@ -37,7 +41,9 @@ import android.net.ipsec.ike.ChildSessionCallback; import android.net.ipsec.ike.ChildSessionConfiguration; import android.net.ipsec.ike.IkeSessionCallback; import android.net.ipsec.ike.IkeSessionConfiguration; +import android.net.ipsec.ike.IkeSessionConnectionInfo; import android.net.ipsec.ike.IkeTrafficSelector; +import android.net.ipsec.ike.TunnelModeChildSessionParams; import android.net.ipsec.ike.cts.TestNetworkUtils.TestNetworkCallback; import android.net.ipsec.ike.exceptions.IkeException; import android.net.ipsec.ike.exceptions.IkeProtocolException; @@ -60,6 +66,7 @@ import org.junit.runner.RunWith; import java.net.Inet4Address; import java.net.InetAddress; import java.util.HashSet; +import java.util.List; import java.util.Objects; import java.util.Set; import java.util.concurrent.CompletableFuture; @@ -90,9 +97,13 @@ abstract class IkeSessionTestBase extends IkeTestBase { InetAddresses.parseNumericAddress("198.51.100.10"); static final LinkAddress EXPECTED_INTERNAL_LINK_ADDR = new LinkAddress(EXPECTED_INTERNAL_ADDR, IP4_PREFIX_LEN); - static final IkeTrafficSelector EXPECTED_INBOUND_TS = + + static final IkeTrafficSelector TUNNEL_MODE_INBOUND_TS = new IkeTrafficSelector( MIN_PORT, MAX_PORT, EXPECTED_INTERNAL_ADDR, EXPECTED_INTERNAL_ADDR); + static final IkeTrafficSelector TUNNEL_MODE_OUTBOUND_TS = DEFAULT_V4_TS; + + static final long IKE_DETERMINISTIC_INITIATOR_SPI = Long.parseLong("46B8ECA1E0D72A18", 16); // Static state to reduce setup/teardown static Context sContext = InstrumentationRegistry.getContext(); @@ -238,6 +249,45 @@ abstract class IkeSessionTestBase extends IkeTestBase { } } + TunnelModeChildSessionParams buildTunnelModeChildSessionParams() { + return new TunnelModeChildSessionParams.Builder() + .addSaProposal(SaProposalTest.buildChildSaProposalWithNormalModeCipher()) + .addSaProposal(SaProposalTest.buildChildSaProposalWithCombinedModeCipher()) + .addInternalAddressRequest(AF_INET) + .addInternalAddressRequest(AF_INET6) + .build(); + } + + void performSetupIkeAndFirstChildBlocking(String ikeInitRespHex, String ikeAuthRespHex) + throws Exception { + mTunUtils.awaitReqAndInjectResp( + IKE_DETERMINISTIC_INITIATOR_SPI, + 0 /* expectedMsgId */, + false /* expectedUseEncap */, + ikeInitRespHex); + + mTunUtils.awaitReqAndInjectResp( + IKE_DETERMINISTIC_INITIATOR_SPI, + 1 /* expectedMsgId */, + true /* expectedUseEncap */, + ikeAuthRespHex); + } + + void performSetupIkeAndFirstChildBlocking( + String ikeInitRespHex, int expectedAuthReqPktCnt, String... ikeAuthRespPktHex) + throws Exception { + // TODO: Implemented in followup CL (aosp/1308675) to support awaiting multiple IKE AUTH + // request fragments and injecting multiple IKE AUTH response fragments + } + + void performCloseIkeBlocking(int expectedMsgId, String deleteIkeRespHex) throws Exception { + mTunUtils.awaitReqAndInjectResp( + IKE_DETERMINISTIC_INITIATOR_SPI, + expectedMsgId, + true /* expectedUseEncap */, + deleteIkeRespHex); + } + /** Testing callback that allows caller to block current thread until a method get called */ static class TestIkeSessionCallback implements IkeSessionCallback { private CompletableFuture mFutureIkeConfig = @@ -392,6 +442,47 @@ abstract class IkeSessionTestBase extends IkeTestBase { } } + void verifyIkeSessionSetupBlocking() throws Exception { + IkeSessionConfiguration ikeConfig = mIkeSessionCallback.awaitIkeConfig(); + assertNotNull(ikeConfig); + assertEquals(EXPECTED_REMOTE_APP_VERSION_EMPTY, ikeConfig.getRemoteApplicationVersion()); + assertTrue(ikeConfig.getRemoteVendorIds().isEmpty()); + assertTrue(ikeConfig.getPcscfServers().isEmpty()); + assertTrue(ikeConfig.isIkeExtensionEnabled(EXTENSION_TYPE_FRAGMENTATION)); + + IkeSessionConnectionInfo ikeConnectInfo = ikeConfig.getIkeSessionConnectionInfo(); + assertNotNull(ikeConnectInfo); + assertEquals(mLocalAddress, ikeConnectInfo.getLocalAddress()); + assertEquals(mRemoteAddress, ikeConnectInfo.getRemoteAddress()); + assertEquals(mTunNetwork, ikeConnectInfo.getNetwork()); + } + + void verifyChildSessionSetupBlocking( + TestChildSessionCallback childCallback, + List expectedInboundTs, + List expectedOutboundTs, + List expectedInternalAddresses) + throws Exception { + ChildSessionConfiguration childConfig = childCallback.awaitChildConfig(); + assertNotNull(childConfig); + assertEquals(expectedInboundTs, childConfig.getInboundTrafficSelectors()); + assertEquals(expectedOutboundTs, childConfig.getOutboundTrafficSelectors()); + assertEquals(expectedInternalAddresses, childConfig.getInternalAddresses()); + assertTrue(childConfig.getInternalSubnets().isEmpty()); + assertTrue(childConfig.getInternalDnsServers().isEmpty()); + assertTrue(childConfig.getInternalDhcpServers().isEmpty()); + } + + void verifyCloseIkeAndChildBlocking( + IpSecTransformCallRecord expectedTransformRecordA, + IpSecTransformCallRecord expectedTransformRecordB) + throws Exception { + verifyDeleteIpSecTransformPair( + mFirstChildSessionCallback, expectedTransformRecordA, expectedTransformRecordB); + mFirstChildSessionCallback.awaitOnClosed(); + mIkeSessionCallback.awaitOnClosed(); + } + static void verifyCreateIpSecTransformPair( IpSecTransformCallRecord transformRecordA, IpSecTransformCallRecord transformRecordB) { IpSecTransform transformA = transformRecordA.ipSecTransform; diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java index f52b88ba3a..2bff63a753 100644 --- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java +++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java @@ -26,6 +26,8 @@ import static android.net.ipsec.ike.cts.PacketUtils.UDP_HDRLEN; import static android.net.ipsec.ike.cts.PacketUtils.UdpHeader; import static android.system.OsConstants.IPPROTO_UDP; +import static com.android.internal.util.HexDump.hexStringToByteArray; + import static org.junit.Assert.fail; import android.os.ParcelFileDescriptor; @@ -35,6 +37,7 @@ import java.net.Inet6Address; import java.net.InetAddress; import java.nio.ByteBuffer; import java.util.Arrays; +import java.util.function.Predicate; public class IkeTunUtils extends TunUtils { private static final int PORT_LEN = 2; @@ -54,17 +57,24 @@ public class IkeTunUtils extends TunUtils { /** * Await the expected IKE request and inject an IKE response. * - * @param respIkePkt IKE response packet without IP/UDP headers or NON ESP MARKER. + * @param ikeRespDataHex IKE response hex without IP/UDP headers or NON ESP MARKER. */ public byte[] awaitReqAndInjectResp( - long expectedInitIkeSpi, int expectedMsgId, boolean expectedUseEncap, byte[] respIkePkt) + long expectedInitIkeSpi, + int expectedMsgId, + boolean expectedUseEncap, + String ikeRespDataHex) throws Exception { byte[] request = awaitIkePacket( - expectedInitIkeSpi, - expectedMsgId, - false /* expectedResp */, - expectedUseEncap); + (pkt) -> { + return isExpectedIkePkt( + pkt, + expectedInitIkeSpi, + expectedMsgId, + false /* expectedResp */, + expectedUseEncap); + }); // Build response header by flipping address and port InetAddress srcAddr = getAddress(request, false /* shouldGetSource */); @@ -73,32 +83,26 @@ public class IkeTunUtils extends TunUtils { int dstPort = getPort(request, true /* shouldGetSource */); byte[] response = - buildIkePacket(srcAddr, dstAddr, srcPort, dstPort, expectedUseEncap, respIkePkt); + buildIkePacket( + srcAddr, + dstAddr, + srcPort, + dstPort, + expectedUseEncap, + hexStringToByteArray(ikeRespDataHex)); injectPacket(response); return request; } - private byte[] awaitIkePacket( - long expectedInitIkeSpi, - int expectedMsgId, - boolean expectedResp, - boolean expectedUseEncap) - throws Exception { + // TODO: Implemented in followup CL (aosp/1308675) to support awaiting multiple + // request fragments and injecting multiple response fragments + + private byte[] awaitIkePacket(Predicate pktVerifier) throws Exception { long endTime = System.currentTimeMillis() + TIMEOUT; int startIndex = 0; synchronized (mPackets) { while (System.currentTimeMillis() < endTime) { - byte[] ikePkt = - getFirstMatchingPacket( - (pkt) -> { - return isIke( - pkt, - expectedInitIkeSpi, - expectedMsgId, - expectedResp, - expectedUseEncap); - }, - startIndex); + byte[] ikePkt = getFirstMatchingPacket(pktVerifier, startIndex); if (ikePkt != null) { return ikePkt; // We've found the packet we're looking for. } @@ -112,21 +116,14 @@ public class IkeTunUtils extends TunUtils { } } - String direction = expectedResp ? "response" : "request"; - fail( - "No such IKE " - + direction - + " found with Initiator SPI " - + expectedInitIkeSpi - + " and message ID " - + expectedMsgId); + fail("No matching packet found"); } throw new IllegalStateException( "Hit an impossible case where fail() didn't throw an exception"); } - private static boolean isIke( + private static boolean isExpectedIkePkt( byte[] pkt, long expectedInitIkeSpi, int expectedMsgId, @@ -153,7 +150,7 @@ public class IkeTunUtils extends TunUtils { } return pkt[ipProtocolOffset] == IPPROTO_UDP - && areSpiAndMsgIdEqual( + && isExpectedSpiAndMsgId( pkt, ikeOffset, expectedInitIkeSpi, expectedMsgId, expectedResp); } @@ -170,10 +167,10 @@ public class IkeTunUtils extends TunUtils { return Arrays.equals(NON_ESP_MARKER, nonEspMarker); } - private static boolean areSpiAndMsgIdEqual( + private static boolean isExpectedSpiAndMsgId( byte[] pkt, int ikeOffset, - long expectedIkeInitSpi, + long expectedInitIkeSpi, int expectedMsgId, boolean expectedResp) { if (pkt.length <= ikeOffset + IKE_HEADER_LEN) return false;