Merge "Move common logic in testing and verification to IkeSessionTestBase"

This commit is contained in:
Yan Yan
2020-05-26 22:51:40 +00:00
committed by Gerrit Code Review
3 changed files with 153 additions and 134 deletions

View File

@@ -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<LinkAddress>());
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();

View File

@@ -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<IkeSessionConfiguration> 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<IkeTrafficSelector> expectedInboundTs,
List<IkeTrafficSelector> expectedOutboundTs,
List<LinkAddress> 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;

View File

@@ -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<byte[]> 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;