From 3c0ad1ddcc2ba5855dbb0392160b1f38ce49cbc6 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 14 Mar 2018 17:35:30 -0700 Subject: [PATCH 1/4] Add GCM to algorithms tested in CTS This change adds all combinations of GCM algorithms, ensuring proper support, config flags, and data accounting. Algorithm for calculating size of packets has also been made more generic to allow for calculation based on different encryption algorithms. Bug: 73261868 Test: This Merged-In: Ib77ac237fee75415223f0291cecc0b60ce76b77f Change-Id: Ib77ac237fee75415223f0291cecc0b60ce76b77f (cherry picked from commit f64579bceb6287f09503d940619d096aa8c1ac0d) --- .../src/android/net/cts/IpSecManagerTest.java | 496 +++++++++++------- 1 file changed, 306 insertions(+), 190 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java index 6a6dd84806..8e99a13fd9 100644 --- a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java @@ -70,19 +70,18 @@ public class IpSecManagerTest extends AndroidTestCase { private static final int DROID_SPI = 0xD1201D; private static final int MAX_PORT_BIND_ATTEMPTS = 10; - private static final byte[] CRYPT_KEY = { + private static final byte[] KEY_DATA = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F - }; - private static final byte[] AUTH_KEY = { - 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, - 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23 }; + private static final byte[] AUTH_KEY = getKey(256); + private static final byte[] CRYPT_KEY = getKey(256); + private static final byte[] AEAD_KEY = getKey(288); + private static final String IPV4_LOOPBACK = "127.0.0.1"; private static final String IPV6_LOOPBACK = "::1"; private static final int TCP_HDRLEN_WITH_OPTIONS = 32; @@ -93,7 +92,9 @@ public class IpSecManagerTest extends AndroidTestCase { private static final byte[] TEST_DATA = "Best test data ever!".getBytes(); // Encryption parameters + private static final int AES_GCM_IV_LEN = 8; private static final int AES_CBC_IV_LEN = 16; + private static final int AES_GCM_BLK_SIZE = 4; private static final int AES_CBC_BLK_SIZE = 16; protected void setUp() throws Exception { @@ -132,8 +133,8 @@ public class IpSecManagerTest extends AndroidTestCase { } } - private byte[] getAuthKey(int bitLength) { - return Arrays.copyOf(AUTH_KEY, bitLength / 8); + private static byte[] getKey(int bitLength) { + return Arrays.copyOf(KEY_DATA, bitLength / 8); } private static int getDomain(InetAddress address) { @@ -273,9 +274,17 @@ public class IpSecManagerTest extends AndroidTestCase { StatsChecker.waitForNumPackets(4 * (i + 1)); } - mISM.removeTransportModeTransforms(server); - mISM.removeTransportModeTransforms(client); - mISM.removeTransportModeTransforms(accepted); + // Transforms should not be removed from the sockets, otherwise FIN packets will be sent + // unencrypted. + // This test also unfortunately happens to rely on a nuance of the cleanup order. By + // keeping the policy on the socket, but removing the SA before lingering FIN packets + // are sent (at an undetermined later time), the FIN packets are dropped. Without this, + // we run into all kinds of headaches trying to test data accounting (unsolicited + // packets mysteriously appearing and messing up our counters) + // The right way to close sockets is to set SO_LINGER to ensure synchronous closure, + // closing the sockets, and then closing the transforms. See documentation for the + // Socket or FileDescriptor flavors of applyTransportModeTransform() in IpSecManager + // for more details. Os.close(server); Os.close(client); @@ -299,8 +308,7 @@ public class IpSecManagerTest extends AndroidTestCase { IpSecTransform transform = new IpSecTransform.Builder(mContext) - .setEncryption( - new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY)) + .setEncryption(new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY)) .setAuthentication( new IpSecAlgorithm( IpSecAlgorithm.AUTH_HMAC_SHA256, @@ -363,7 +371,6 @@ public class IpSecManagerTest extends AndroidTestCase { /** Snapshot of TrafficStats as of initStatsChecker call for later comparisons */ private static class StatsChecker { - private static final String LOOPBACK_INTERFACE = "lo"; private static final double ERROR_MARGIN_BYTES = 1.05; private static final double ERROR_MARGIN_PKTS = 1.05; private static final int MAX_WAIT_TIME_MILLIS = 1000; @@ -451,7 +458,7 @@ public class IpSecManagerTest extends AndroidTestCase { assertTrue((expectedDelta * errorMargin) > newStats - oldStats); } - private static void initStatsChecker() throws IOException { + private static void initStatsChecker() throws Exception { uidTxBytes = TrafficStats.getUidTxBytes(Os.getuid()); uidRxBytes = TrafficStats.getUidRxBytes(Os.getuid()); uidTxPackets = TrafficStats.getUidTxPackets(Os.getuid()); @@ -464,35 +471,37 @@ public class IpSecManagerTest extends AndroidTestCase { } } - private int getTruncLenBits(IpSecAlgorithm auth) { - return auth == null ? 0 : auth.getTruncationLengthBits(); + private int getTruncLenBits(IpSecAlgorithm authOrAead) { + return authOrAead == null ? 0 : authOrAead.getTruncationLengthBits(); } - private int getIvLen(IpSecAlgorithm crypt) { - if (crypt == null) { - return 0; - } + private int getIvLen(IpSecAlgorithm cryptOrAead) { + if (cryptOrAead == null) { return 0; } - switch (crypt.getName()) { + switch (cryptOrAead.getName()) { case IpSecAlgorithm.CRYPT_AES_CBC: return AES_CBC_IV_LEN; + case IpSecAlgorithm.AUTH_CRYPT_AES_GCM: + return AES_GCM_IV_LEN; default: throw new IllegalArgumentException( - "IV length unknown for algorithm" + crypt.getName()); + "IV length unknown for algorithm" + cryptOrAead.getName()); } } - private int getBlkSize(IpSecAlgorithm crypt) { - if (crypt == null) { - return 4; - } + private int getBlkSize(IpSecAlgorithm cryptOrAead) { + // RFC 4303, section 2.4 states that ciphertext plus pad_len, next_header fields must + // terminate on a 4-byte boundary. Thus, the minimum ciphertext block size is 4 bytes. + if (cryptOrAead == null) { return 4; } - switch (crypt.getName()) { + switch (cryptOrAead.getName()) { case IpSecAlgorithm.CRYPT_AES_CBC: return AES_CBC_BLK_SIZE; + case IpSecAlgorithm.AUTH_CRYPT_AES_GCM: + return AES_GCM_BLK_SIZE; default: throw new IllegalArgumentException( - "Blk size unknown for algorithm" + crypt.getName()); + "Blk size unknown for algorithm" + cryptOrAead.getName()); } } @@ -514,6 +523,7 @@ public class IpSecManagerTest extends AndroidTestCase { String localAddress, IpSecAlgorithm crypt, IpSecAlgorithm auth, + IpSecAlgorithm aead, boolean doUdpEncap, int sendCount, boolean useJavaSockets) @@ -532,6 +542,9 @@ public class IpSecManagerTest extends AndroidTestCase { if (auth != null) { transformBuilder.setAuthentication(auth); } + if (aead != null) { + transformBuilder.setAuthenticatedEncryption(aead); + } if (doUdpEncap) { transformBuilder = @@ -563,9 +576,9 @@ public class IpSecManagerTest extends AndroidTestCase { transportHdrLen, udpEncapLen, sendCount, - getIvLen(crypt), - getBlkSize(crypt), - getTruncLenBits(auth)); + getIvLen(crypt != null ? crypt : aead), + getBlkSize(crypt != null ? crypt : aead), + getTruncLenBits(auth != null ? auth : aead)); } } @@ -668,346 +681,448 @@ public class IpSecManagerTest extends AndroidTestCase { // public void testInterfaceCountersTcp4() throws Exception { // IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); // IpSecAlgorithm auth = new IpSecAlgorithm( - // IpSecAlgorithm.AUTH_HMAC_MD5, getAuthKey(128), 96); + // IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); // checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, false, 1000); // } // public void testInterfaceCountersTcp6() throws Exception { // IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); // IpSecAlgorithm auth = new IpSecAlgorithm( - // IpSecAlgorithm.AUTH_HMAC_MD5, getAuthKey(128), 96); + // IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); // checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, false, 1000); // } // public void testInterfaceCountersTcp4UdpEncap() throws Exception { // IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); // IpSecAlgorithm auth = - // new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getAuthKey(128), 96); + // new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); // checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, true, 1000); // } public void testInterfaceCountersUdp4() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); - IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getAuthKey(128), 96); - checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, false, 1000, false); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1000, false); } public void testInterfaceCountersUdp6() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); - IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getAuthKey(128), 96); - checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, false, 1000, false); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); + checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1000, false); } public void testInterfaceCountersUdp4UdpEncap() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); - IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getAuthKey(128), 96); - checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, true, 1000, false); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1000, false); } public void testAesCbcHmacMd5Tcp4() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); - IpSecAlgorithm auth = new IpSecAlgorithm( - IpSecAlgorithm.AUTH_HMAC_MD5, getAuthKey(128), 96); - checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, false, 1, false); - checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, false, 1, true); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, false); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true); } public void testAesCbcHmacMd5Tcp6() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); - IpSecAlgorithm auth = new IpSecAlgorithm( - IpSecAlgorithm.AUTH_HMAC_MD5, getAuthKey(128), 96); - checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, false, 1, false); - checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, false, 1, true); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); + checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, false); + checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true); } public void testAesCbcHmacMd5Udp4() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); - IpSecAlgorithm auth = new IpSecAlgorithm( - IpSecAlgorithm.AUTH_HMAC_MD5, getAuthKey(128), 96); - checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, false, 1, false); - checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, false, 1, true); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, false); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true); } public void testAesCbcHmacMd5Udp6() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); - IpSecAlgorithm auth = new IpSecAlgorithm( - IpSecAlgorithm.AUTH_HMAC_MD5, getAuthKey(128), 96); - checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, false, 1, false); - checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, false, 1, true); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); + checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, false); + checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true); } public void testAesCbcHmacSha1Tcp4() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); - IpSecAlgorithm auth = new IpSecAlgorithm( - IpSecAlgorithm.AUTH_HMAC_SHA1, getAuthKey(160), 96); - checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, false, 1, false); - checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, false, 1, true); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, getKey(160), 96); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, false); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true); } public void testAesCbcHmacSha1Tcp6() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); - IpSecAlgorithm auth = new IpSecAlgorithm( - IpSecAlgorithm.AUTH_HMAC_SHA1, getAuthKey(160), 96); - checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, false, 1, false); - checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, false, 1, true); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, getKey(160), 96); + checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, false); + checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true); } public void testAesCbcHmacSha1Udp4() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); - IpSecAlgorithm auth = new IpSecAlgorithm( - IpSecAlgorithm.AUTH_HMAC_SHA1, getAuthKey(160), 96); - checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, false, 1, false); - checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, false, 1, true); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, getKey(160), 96); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, false); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true); } public void testAesCbcHmacSha1Udp6() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); - IpSecAlgorithm auth = new IpSecAlgorithm( - IpSecAlgorithm.AUTH_HMAC_SHA1, getAuthKey(160), 96); - checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, false, 1, false); - checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, false, 1, true); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, getKey(160), 96); + checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, false); + checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true); } public void testAesCbcHmacSha256Tcp4() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); - IpSecAlgorithm auth = new IpSecAlgorithm( - IpSecAlgorithm.AUTH_HMAC_SHA256, getAuthKey(256), 128); - checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, false, 1, false); - checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, false, 1, true); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, false); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true); } public void testAesCbcHmacSha256Tcp6() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); - IpSecAlgorithm auth = new IpSecAlgorithm( - IpSecAlgorithm.AUTH_HMAC_SHA256, getAuthKey(256), 128); - checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, false, 1, false); - checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, false, 1, true); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); + checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, false); + checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true); } public void testAesCbcHmacSha256Udp4() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); - IpSecAlgorithm auth = new IpSecAlgorithm( - IpSecAlgorithm.AUTH_HMAC_SHA256, getAuthKey(256), 128); - checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, false, 1, false); - checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, false, 1, true); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, false); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true); } public void testAesCbcHmacSha256Udp6() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); - IpSecAlgorithm auth = new IpSecAlgorithm( - IpSecAlgorithm.AUTH_HMAC_SHA256, getAuthKey(256), 128); - checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, false, 1, false); - checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, false, 1, true); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); + checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, false); + checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true); } public void testAesCbcHmacSha384Tcp4() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); - IpSecAlgorithm auth = new IpSecAlgorithm( - IpSecAlgorithm.AUTH_HMAC_SHA384, getAuthKey(384), 192); - checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, false, 1, false); - checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, false, 1, true); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA384, getKey(384), 192); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, false); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true); } public void testAesCbcHmacSha384Tcp6() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); - IpSecAlgorithm auth = new IpSecAlgorithm( - IpSecAlgorithm.AUTH_HMAC_SHA384, getAuthKey(384), 192); - checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, false, 1, false); - checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, false, 1, true); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA384, getKey(384), 192); + checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, false); + checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true); } public void testAesCbcHmacSha384Udp4() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); - IpSecAlgorithm auth = new IpSecAlgorithm( - IpSecAlgorithm.AUTH_HMAC_SHA384, getAuthKey(384), 192); - checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, false, 1, false); - checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, false, 1, true); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA384, getKey(384), 192); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, false); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true); } public void testAesCbcHmacSha384Udp6() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); - IpSecAlgorithm auth = new IpSecAlgorithm( - IpSecAlgorithm.AUTH_HMAC_SHA384, getAuthKey(384), 192); - checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, false, 1, false); - checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, false, 1, true); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA384, getKey(384), 192); + checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, false); + checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true); } public void testAesCbcHmacSha512Tcp4() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); - IpSecAlgorithm auth = new IpSecAlgorithm( - IpSecAlgorithm.AUTH_HMAC_SHA512, getAuthKey(512), 256); - checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, false, 1, false); - checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, false, 1, true); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA512, getKey(512), 256); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, false); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true); } public void testAesCbcHmacSha512Tcp6() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); - IpSecAlgorithm auth = new IpSecAlgorithm( - IpSecAlgorithm.AUTH_HMAC_SHA512, getAuthKey(512), 256); - checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, false, 1, false); - checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, false, 1, true); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA512, getKey(512), 256); + checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, false); + checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true); } public void testAesCbcHmacSha512Udp4() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); - IpSecAlgorithm auth = new IpSecAlgorithm( - IpSecAlgorithm.AUTH_HMAC_SHA512, getAuthKey(512), 256); - checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, false, 1, false); - checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, false, 1, true); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA512, getKey(512), 256); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, false); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true); } public void testAesCbcHmacSha512Udp6() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); - IpSecAlgorithm auth = new IpSecAlgorithm( - IpSecAlgorithm.AUTH_HMAC_SHA512, getAuthKey(512), 256); - checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, false, 1, false); - checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, false, 1, true); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA512, getKey(512), 256); + checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, false); + checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true); + } + + public void testAesGcm64Tcp4() throws Exception { + IpSecAlgorithm authCrypt = + new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 64); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, false); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, true); + } + + public void testAesGcm64Tcp6() throws Exception { + IpSecAlgorithm authCrypt = + new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 64); + checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, false); + checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, true); + } + + public void testAesGcm64Udp4() throws Exception { + IpSecAlgorithm authCrypt = + new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 64); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, false); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, true); + } + + public void testAesGcm64Udp6() throws Exception { + IpSecAlgorithm authCrypt = + new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 64); + checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, false); + checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, true); + } + + public void testAesGcm96Tcp4() throws Exception { + IpSecAlgorithm authCrypt = + new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 96); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, false); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, true); + } + + public void testAesGcm96Tcp6() throws Exception { + IpSecAlgorithm authCrypt = + new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 96); + checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, false); + checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, true); + } + + public void testAesGcm96Udp4() throws Exception { + IpSecAlgorithm authCrypt = + new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 96); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, false); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, true); + } + + public void testAesGcm96Udp6() throws Exception { + IpSecAlgorithm authCrypt = + new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 96); + checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, false); + checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, true); + } + + public void testAesGcm128Tcp4() throws Exception { + IpSecAlgorithm authCrypt = + new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, false); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, true); + } + + public void testAesGcm128Tcp6() throws Exception { + IpSecAlgorithm authCrypt = + new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128); + checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, false); + checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, true); + } + + public void testAesGcm128Udp4() throws Exception { + IpSecAlgorithm authCrypt = + new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, false); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, true); + } + + public void testAesGcm128Udp6() throws Exception { + IpSecAlgorithm authCrypt = + new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128); + checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, false); + checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, true); } public void testAesCbcHmacMd5Tcp4UdpEncap() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); - IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getAuthKey(128), 96); - checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, true, 1, false); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, false); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true); } public void testAesCbcHmacMd5Udp4UdpEncap() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); - IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getAuthKey(128), 96); - checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, true, 1, false); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, false); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true); } public void testAesCbcHmacSha1Tcp4UdpEncap() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); - IpSecAlgorithm auth = - new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, getAuthKey(160), 96); - checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, true, 1, false); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, getKey(160), 96); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, false); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true); } public void testAesCbcHmacSha1Udp4UdpEncap() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); - IpSecAlgorithm auth = - new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, getAuthKey(160), 96); - checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, true, 1, false); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, getKey(160), 96); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, false); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true); } public void testAesCbcHmacSha256Tcp4UdpEncap() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); - IpSecAlgorithm auth = - new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getAuthKey(256), 128); - checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, true, 1, false); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, false); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true); } public void testAesCbcHmacSha256Udp4UdpEncap() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); - IpSecAlgorithm auth = - new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getAuthKey(256), 128); - checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, true, 1, false); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, false); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true); } public void testAesCbcHmacSha384Tcp4UdpEncap() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); - IpSecAlgorithm auth = - new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA384, getAuthKey(384), 192); - checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, true, 1, false); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA384, getKey(384), 192); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, false); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true); } public void testAesCbcHmacSha384Udp4UdpEncap() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); - IpSecAlgorithm auth = - new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA384, getAuthKey(384), 192); - checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, true, 1, false); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA384, getKey(384), 192); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, false); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true); } public void testAesCbcHmacSha512Tcp4UdpEncap() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); - IpSecAlgorithm auth = - new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA512, getAuthKey(512), 256); - checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, true, 1, false); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA512, getKey(512), 256); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, false); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true); } public void testAesCbcHmacSha512Udp4UdpEncap() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); - IpSecAlgorithm auth = - new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA512, getAuthKey(512), 256); - checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, true, 1, false); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA512, getKey(512), 256); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, false); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true); + } + + public void testAesGcm64Tcp4UdpEncap() throws Exception { + IpSecAlgorithm authCrypt = + new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 64); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, false); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, true); + } + + public void testAesGcm64Udp4UdpEncap() throws Exception { + IpSecAlgorithm authCrypt = + new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 64); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, false); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, true); + } + + public void testAesGcm96Tcp4UdpEncap() throws Exception { + IpSecAlgorithm authCrypt = + new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 96); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, false); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, true); + } + + public void testAesGcm96Udp4UdpEncap() throws Exception { + IpSecAlgorithm authCrypt = + new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 96); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, false); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, true); + } + + public void testAesGcm128Tcp4UdpEncap() throws Exception { + IpSecAlgorithm authCrypt = + new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, false); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, true); + } + + public void testAesGcm128Udp4UdpEncap() throws Exception { + IpSecAlgorithm authCrypt = + new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, false); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, true); } public void testCryptUdp4() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); - checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, null, false, 1, false); - checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, null, false, 1, true); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, null, null, false, 1, false); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, null, null, false, 1, true); } public void testAuthUdp4() throws Exception { - IpSecAlgorithm auth = - new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getAuthKey(256), 128); - checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, auth, false, 1, false); - checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, auth, false, 1, true); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, auth, null, false, 1, false); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, auth, null, false, 1, true); } public void testCryptUdp6() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); - checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, null, false, 1, false); - checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, null, false, 1, true); + checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, null, null, false, 1, false); + checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, null, null, false, 1, true); } public void testAuthUdp6() throws Exception { - IpSecAlgorithm auth = - new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getAuthKey(256), 128); - checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, null, auth, false, 1, false); - checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, null, auth, false, 1, true); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); + checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, null, auth, null, false, 1, false); + checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, null, auth, null, false, 1, true); } public void testCryptTcp4() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); - checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, null, false, 1, false); - checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, null, false, 1, true); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, null, null, false, 1, false); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, null, null, false, 1, true); } public void testAuthTcp4() throws Exception { - IpSecAlgorithm auth = - new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getAuthKey(256), 128); - checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, auth, false, 1, false); - checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, auth, false, 1, true); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, auth, null, false, 1, false); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, auth, null, false, 1, true); } public void testCryptTcp6() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); - checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, null, false, 1, false); - checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, null, false, 1, true); + checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, null, null, false, 1, false); + checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, null, null, false, 1, true); } public void testAuthTcp6() throws Exception { - IpSecAlgorithm auth = - new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getAuthKey(256), 128); - checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, auth, false, 1, false); - checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, auth, false, 1, true); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); + checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, auth, null, false, 1, false); + checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, auth, null, false, 1, true); } public void testCryptUdp4UdpEncap() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); - checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, null, true, 1, false); - checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, null, true, 1, true); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, null, null, true, 1, false); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, null, null, true, 1, true); } public void testAuthUdp4UdpEncap() throws Exception { - IpSecAlgorithm auth = - new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getAuthKey(256), 128); - checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, auth, true, 1, false); - checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, auth, true, 1, true); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, auth, null, true, 1, false); + checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, auth, null, true, 1, true); } public void testCryptTcp4UdpEncap() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); - checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, null, true, 1, false); - checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, null, true, 1, true); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, null, null, true, 1, false); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, null, null, true, 1, true); } public void testAuthTcp4UdpEncap() throws Exception { - IpSecAlgorithm auth = - new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getAuthKey(256), 128); - checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, auth, true, 1, false); - checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, auth, true, 1, true); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, auth, null, true, 1, false); + checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, auth, null, true, 1, true); } public void testOpenUdpEncapSocketSpecificPort() throws Exception { @@ -1180,11 +1295,12 @@ public class IpSecManagerTest extends AndroidTestCase { String localAddr = (remoteAddr instanceof Inet4Address) ? IPV4_LOOPBACK : IPV6_LOOPBACK; return new IpSecTransform.Builder(mContext) - .setEncryption( - new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY)) + .setEncryption(new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY)) .setAuthentication( new IpSecAlgorithm( - IpSecAlgorithm.AUTH_HMAC_SHA256, AUTH_KEY, AUTH_KEY.length * 4)) + IpSecAlgorithm.AUTH_HMAC_SHA256, + AUTH_KEY, + AUTH_KEY.length * 4)) .setIpv4Encapsulation(encapSocket, encapSocket.getPort()) .buildTransportModeTransform(InetAddress.getByName(localAddr), spi); } From c33ed347f08b3dfbf7f188b4deb876f1af9f0f4a Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 22 Mar 2018 10:15:31 -0700 Subject: [PATCH 2/4] Add generic socket interfaces and functions This patch adds functionality to unify java and native sockets. This is part one of two of a change to allow functionality for testing full coverage of all APIs. Bug: 76152303 Test: Ran tests on Walleye Merged-In: I9bd57d6267f82d8c1ac293a0147dc2c115dd4181 Change-Id: I9bd57d6267f82d8c1ac293a0147dc2c115dd4181 (cherry picked from commit d524e0785c7bbe5c7987f8ae01fdc5d57e13545d) --- .../src/android/net/cts/IpSecBaseTest.java | 497 ++++++++++++++++++ .../src/android/net/cts/IpSecManagerTest.java | 57 +- 2 files changed, 498 insertions(+), 56 deletions(-) create mode 100644 tests/cts/net/src/android/net/cts/IpSecBaseTest.java diff --git a/tests/cts/net/src/android/net/cts/IpSecBaseTest.java b/tests/cts/net/src/android/net/cts/IpSecBaseTest.java new file mode 100644 index 0000000000..57cfe2a9e9 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/IpSecBaseTest.java @@ -0,0 +1,497 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.cts; + +import static org.junit.Assert.assertArrayEquals; + +import android.content.Context; +import android.net.IpSecAlgorithm; +import android.net.IpSecManager; +import android.net.IpSecTransform; +import android.system.Os; +import android.system.OsConstants; +import android.test.AndroidTestCase; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketException; +import java.util.Arrays; + +public class IpSecBaseTest extends AndroidTestCase { + + private static final String TAG = IpSecBaseTest.class.getSimpleName(); + + protected static final String IPV4_LOOPBACK = "127.0.0.1"; + protected static final String IPV6_LOOPBACK = "::1"; + protected static final String[] LOOPBACK_ADDRS = new String[] {IPV4_LOOPBACK, IPV6_LOOPBACK}; + protected static final int[] DIRECTIONS = + new int[] {IpSecManager.DIRECTION_IN, IpSecManager.DIRECTION_OUT}; + + protected static final byte[] TEST_DATA = "Best test data ever!".getBytes(); + protected static final int DATA_BUFFER_LEN = 4096; + + private static final byte[] KEY_DATA = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23 + }; + + protected static final byte[] AUTH_KEY = getKey(256); + protected static final byte[] CRYPT_KEY = getKey(256); + + protected IpSecManager mISM; + + protected void setUp() throws Exception { + super.setUp(); + mISM = (IpSecManager) getContext().getSystemService(Context.IPSEC_SERVICE); + } + + protected static byte[] getKey(int bitLength) { + return Arrays.copyOf(KEY_DATA, bitLength / 8); + } + + protected static int getDomain(InetAddress address) { + int domain; + if (address instanceof Inet6Address) { + domain = OsConstants.AF_INET6; + } else { + domain = OsConstants.AF_INET; + } + return domain; + } + + protected static int getPort(FileDescriptor sock) throws Exception { + return ((InetSocketAddress) Os.getsockname(sock)).getPort(); + } + + public static interface GenericSocket extends AutoCloseable { + void send(byte[] data) throws Exception; + + byte[] receive() throws Exception; + + int getPort() throws Exception; + + void close() throws Exception; + + void applyTransportModeTransform( + IpSecManager ism, int direction, IpSecTransform transform) throws Exception; + + void removeTransportModeTransforms(IpSecManager ism) throws Exception; + } + + public static interface GenericTcpSocket extends GenericSocket {} + + public static interface GenericUdpSocket extends GenericSocket { + void sendTo(byte[] data, InetAddress dstAddr, int port) throws Exception; + } + + public abstract static class NativeSocket implements GenericSocket { + public FileDescriptor mFd; + + public NativeSocket(FileDescriptor fd) { + mFd = fd; + } + + @Override + public void send(byte[] data) throws Exception { + Os.write(mFd, data, 0, data.length); + } + + @Override + public byte[] receive() throws Exception { + byte[] in = new byte[DATA_BUFFER_LEN]; + int bytesRead = Os.read(mFd, in, 0, DATA_BUFFER_LEN); + + return Arrays.copyOfRange(in, 0, bytesRead); + } + + @Override + public int getPort() throws Exception { + return IpSecBaseTest.getPort(mFd); + } + + @Override + public void close() throws Exception { + Os.close(mFd); + } + + @Override + public void applyTransportModeTransform( + IpSecManager ism, int direction, IpSecTransform transform) throws Exception { + ism.applyTransportModeTransform(mFd, direction, transform); + } + + @Override + public void removeTransportModeTransforms(IpSecManager ism) throws Exception { + ism.removeTransportModeTransforms(mFd); + } + } + + public static class NativeTcpSocket extends NativeSocket implements GenericTcpSocket { + public NativeTcpSocket(FileDescriptor fd) { + super(fd); + } + } + + public static class NativeUdpSocket extends NativeSocket implements GenericUdpSocket { + public NativeUdpSocket(FileDescriptor fd) { + super(fd); + } + + @Override + public void sendTo(byte[] data, InetAddress dstAddr, int port) throws Exception { + Os.sendto(mFd, data, 0, data.length, 0, dstAddr, port); + } + } + + public static class JavaUdpSocket implements GenericUdpSocket { + public final DatagramSocket mSocket; + + public JavaUdpSocket(InetAddress localAddr) { + try { + mSocket = new DatagramSocket(0, localAddr); + mSocket.setSoTimeout(500); + } catch (SocketException e) { + // Fail loudly if we can't set up sockets properly. And without the timeout, we + // could easily end up in an endless wait. + throw new RuntimeException(e); + } + } + + @Override + public void send(byte[] data) throws Exception { + mSocket.send(new DatagramPacket(data, data.length)); + } + + @Override + public void sendTo(byte[] data, InetAddress dstAddr, int port) throws Exception { + mSocket.send(new DatagramPacket(data, data.length, dstAddr, port)); + } + + @Override + public int getPort() throws Exception { + return mSocket.getLocalPort(); + } + + @Override + public void close() throws Exception { + mSocket.close(); + } + + @Override + public byte[] receive() throws Exception { + DatagramPacket data = new DatagramPacket(new byte[DATA_BUFFER_LEN], DATA_BUFFER_LEN); + mSocket.receive(data); + return Arrays.copyOfRange(data.getData(), 0, data.getLength()); + } + + @Override + public void applyTransportModeTransform( + IpSecManager ism, int direction, IpSecTransform transform) throws Exception { + ism.applyTransportModeTransform(mSocket, direction, transform); + } + + @Override + public void removeTransportModeTransforms(IpSecManager ism) throws Exception { + ism.removeTransportModeTransforms(mSocket); + } + } + + public static class JavaTcpSocket implements GenericTcpSocket { + public final Socket mSocket; + + public JavaTcpSocket(Socket socket) { + mSocket = socket; + try { + mSocket.setSoTimeout(500); + } catch (SocketException e) { + // Fail loudly if we can't set up sockets properly. And without the timeout, we + // could easily end up in an endless wait. + throw new RuntimeException(e); + } + } + + @Override + public void send(byte[] data) throws Exception { + mSocket.getOutputStream().write(data); + } + + @Override + public byte[] receive() throws Exception { + byte[] in = new byte[DATA_BUFFER_LEN]; + int bytesRead = mSocket.getInputStream().read(in); + return Arrays.copyOfRange(in, 0, bytesRead); + } + + @Override + public int getPort() throws Exception { + return mSocket.getLocalPort(); + } + + @Override + public void close() throws Exception { + mSocket.close(); + } + + @Override + public void applyTransportModeTransform( + IpSecManager ism, int direction, IpSecTransform transform) throws Exception { + ism.applyTransportModeTransform(mSocket, direction, transform); + } + + @Override + public void removeTransportModeTransforms(IpSecManager ism) throws Exception { + ism.removeTransportModeTransforms(mSocket); + } + } + + public static class SocketPair { + public final T mLeftSock; + public final T mRightSock; + + public SocketPair(T leftSock, T rightSock) { + mLeftSock = leftSock; + mRightSock = rightSock; + } + } + + private static void applyTransformBidirectionally( + IpSecManager ism, IpSecTransform transform, GenericSocket socket) throws Exception { + for (int direction : DIRECTIONS) { + socket.applyTransportModeTransform(ism, direction, transform); + } + } + + public static SocketPair getNativeUdpSocketPair( + InetAddress localAddr, IpSecManager ism, IpSecTransform transform, boolean connected) + throws Exception { + int domain = getDomain(localAddr); + + NativeUdpSocket leftSock = new NativeUdpSocket( + Os.socket(domain, OsConstants.SOCK_DGRAM, OsConstants.IPPROTO_UDP)); + NativeUdpSocket rightSock = new NativeUdpSocket( + Os.socket(domain, OsConstants.SOCK_DGRAM, OsConstants.IPPROTO_UDP)); + + for (NativeUdpSocket sock : new NativeUdpSocket[] {leftSock, rightSock}) { + applyTransformBidirectionally(ism, transform, sock); + Os.bind(sock.mFd, localAddr, 0); + } + + if (connected) { + Os.connect(leftSock.mFd, localAddr, rightSock.getPort()); + Os.connect(rightSock.mFd, localAddr, leftSock.getPort()); + } + + return new SocketPair<>(leftSock, rightSock); + } + + public static SocketPair getNativeTcpSocketPair( + InetAddress localAddr, IpSecManager ism, IpSecTransform transform) throws Exception { + int domain = getDomain(localAddr); + + NativeTcpSocket server = new NativeTcpSocket( + Os.socket(domain, OsConstants.SOCK_STREAM, OsConstants.IPPROTO_TCP)); + NativeTcpSocket client = new NativeTcpSocket( + Os.socket(domain, OsConstants.SOCK_STREAM, OsConstants.IPPROTO_TCP)); + + Os.bind(server.mFd, localAddr, 0); + + applyTransformBidirectionally(ism, transform, server); + applyTransformBidirectionally(ism, transform, client); + + Os.listen(server.mFd, 10); + Os.connect(client.mFd, localAddr, server.getPort()); + NativeTcpSocket accepted = new NativeTcpSocket(Os.accept(server.mFd, null)); + + applyTransformBidirectionally(ism, transform, accepted); + server.close(); + + return new SocketPair<>(client, accepted); + } + + public static SocketPair getJavaUdpSocketPair( + InetAddress localAddr, IpSecManager ism, IpSecTransform transform, boolean connected) + throws Exception { + JavaUdpSocket leftSock = new JavaUdpSocket(localAddr); + JavaUdpSocket rightSock = new JavaUdpSocket(localAddr); + + applyTransformBidirectionally(ism, transform, leftSock); + applyTransformBidirectionally(ism, transform, rightSock); + + if (connected) { + leftSock.mSocket.connect(localAddr, rightSock.mSocket.getLocalPort()); + rightSock.mSocket.connect(localAddr, leftSock.mSocket.getLocalPort()); + } + + return new SocketPair<>(leftSock, rightSock); + } + + public static SocketPair getJavaTcpSocketPair( + InetAddress localAddr, IpSecManager ism, IpSecTransform transform) throws Exception { + JavaTcpSocket clientSock = new JavaTcpSocket(new Socket()); + ServerSocket serverSocket = new ServerSocket(); + serverSocket.bind(new InetSocketAddress(localAddr, 0)); + + // While technically the client socket does not need to be bound, the OpenJDK implementation + // of Socket only allocates an FD when bind() or connect() or other similar methods are + // called. So we call bind to force the FD creation, so that we can apply a transform to it + // prior to socket connect. + clientSock.mSocket.bind(new InetSocketAddress(localAddr, 0)); + + // IpSecService doesn't support serverSockets at the moment; workaround using FD + FileDescriptor serverFd = serverSocket.getImpl().getFD$(); + + applyTransformBidirectionally(ism, transform, new NativeTcpSocket(serverFd)); + applyTransformBidirectionally(ism, transform, clientSock); + + clientSock.mSocket.connect(new InetSocketAddress(localAddr, serverSocket.getLocalPort())); + JavaTcpSocket acceptedSock = new JavaTcpSocket(serverSocket.accept()); + + applyTransformBidirectionally(ism, transform, acceptedSock); + serverSocket.close(); + + return new SocketPair<>(clientSock, acceptedSock); + } + + private void checkSocketPair(GenericSocket left, GenericSocket right) throws Exception { + left.send(TEST_DATA); + assertArrayEquals(TEST_DATA, right.receive()); + + right.send(TEST_DATA); + assertArrayEquals(TEST_DATA, left.receive()); + + left.close(); + right.close(); + } + + private void checkUnconnectedUdpSocketPair( + GenericUdpSocket left, GenericUdpSocket right, InetAddress localAddr) throws Exception { + left.sendTo(TEST_DATA, localAddr, right.getPort()); + assertArrayEquals(TEST_DATA, right.receive()); + + right.sendTo(TEST_DATA, localAddr, left.getPort()); + assertArrayEquals(TEST_DATA, left.receive()); + + left.close(); + right.close(); + } + + protected static IpSecTransform buildIpSecTransform( + Context mContext, + IpSecManager.SecurityParameterIndex spi, + IpSecManager.UdpEncapsulationSocket encapSocket, + InetAddress remoteAddr) + throws Exception { + String localAddr = (remoteAddr instanceof Inet4Address) ? IPV4_LOOPBACK : IPV6_LOOPBACK; + IpSecTransform.Builder builder = + new IpSecTransform.Builder(mContext) + .setEncryption(new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY)) + .setAuthentication( + new IpSecAlgorithm( + IpSecAlgorithm.AUTH_HMAC_SHA256, + AUTH_KEY, + AUTH_KEY.length * 4)); + + if (encapSocket != null) { + builder.setIpv4Encapsulation(encapSocket, encapSocket.getPort()); + } + + return builder.buildTransportModeTransform(InetAddress.getByName(localAddr), spi); + } + + private IpSecTransform buildDefaultTransform(InetAddress localAddr) throws Exception { + try (IpSecManager.SecurityParameterIndex spi = + mISM.allocateSecurityParameterIndex(localAddr)) { + return buildIpSecTransform(mContext, spi, null, localAddr); + } + } + + public void testJavaTcpSocketPair() throws Exception { + for (String addr : LOOPBACK_ADDRS) { + InetAddress local = InetAddress.getByName(addr); + try (IpSecTransform transform = buildDefaultTransform(local)) { + SocketPair sockets = getJavaTcpSocketPair(local, mISM, transform); + checkSocketPair(sockets.mLeftSock, sockets.mRightSock); + } + } + } + + public void testJavaUdpSocketPair() throws Exception { + for (String addr : LOOPBACK_ADDRS) { + InetAddress local = InetAddress.getByName(addr); + try (IpSecTransform transform = buildDefaultTransform(local)) { + SocketPair sockets = + getJavaUdpSocketPair(local, mISM, transform, true); + checkSocketPair(sockets.mLeftSock, sockets.mRightSock); + } + } + } + + public void testJavaUdpSocketPairUnconnected() throws Exception { + for (String addr : LOOPBACK_ADDRS) { + InetAddress local = InetAddress.getByName(addr); + try (IpSecTransform transform = buildDefaultTransform(local)) { + SocketPair sockets = + getJavaUdpSocketPair(local, mISM, transform, false); + checkUnconnectedUdpSocketPair(sockets.mLeftSock, sockets.mRightSock, local); + } + } + } + + public void testNativeTcpSocketPair() throws Exception { + for (String addr : LOOPBACK_ADDRS) { + InetAddress local = InetAddress.getByName(addr); + try (IpSecTransform transform = buildDefaultTransform(local)) { + SocketPair sockets = + getNativeTcpSocketPair(local, mISM, transform); + checkSocketPair(sockets.mLeftSock, sockets.mRightSock); + } + } + } + + public void testNativeUdpSocketPair() throws Exception { + for (String addr : LOOPBACK_ADDRS) { + InetAddress local = InetAddress.getByName(addr); + try (IpSecTransform transform = buildDefaultTransform(local)) { + SocketPair sockets = + getNativeUdpSocketPair(local, mISM, transform, true); + checkSocketPair(sockets.mLeftSock, sockets.mRightSock); + } + } + } + + public void testNativeUdpSocketPairUnconnected() throws Exception { + for (String addr : LOOPBACK_ADDRS) { + InetAddress local = InetAddress.getByName(addr); + try (IpSecTransform transform = buildDefaultTransform(local)) { + SocketPair sockets = + getNativeUdpSocketPair(local, mISM, transform, false); + checkUnconnectedUdpSocketPair(sockets.mLeftSock, sockets.mRightSock, local); + } + } + } +} diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java index 8e99a13fd9..cdbc113c73 100644 --- a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java @@ -31,13 +31,11 @@ import android.os.ParcelFileDescriptor; import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; -import android.test.AndroidTestCase; import java.io.FileDescriptor; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; -import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetSocketAddress; @@ -45,12 +43,10 @@ import java.net.Socket; import java.net.UnknownHostException; import java.util.Arrays; -public class IpSecManagerTest extends AndroidTestCase { +public class IpSecManagerTest extends IpSecBaseTest { private static final String TAG = IpSecManagerTest.class.getSimpleName(); - private IpSecManager mISM; - private ConnectivityManager mCM; private static InetAddress IpAddress(String addrString) { @@ -70,27 +66,13 @@ public class IpSecManagerTest extends AndroidTestCase { private static final int DROID_SPI = 0xD1201D; private static final int MAX_PORT_BIND_ATTEMPTS = 10; - private static final byte[] KEY_DATA = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, - 0x20, 0x21, 0x22, 0x23 - }; - - private static final byte[] AUTH_KEY = getKey(256); - private static final byte[] CRYPT_KEY = getKey(256); private static final byte[] AEAD_KEY = getKey(288); - private static final String IPV4_LOOPBACK = "127.0.0.1"; - private static final String IPV6_LOOPBACK = "::1"; private static final int TCP_HDRLEN_WITH_OPTIONS = 32; private static final int UDP_HDRLEN = 8; private static final int IP4_HDRLEN = 20; private static final int IP6_HDRLEN = 40; - private static final byte[] TEST_DATA = "Best test data ever!".getBytes(); - // Encryption parameters private static final int AES_GCM_IV_LEN = 8; private static final int AES_CBC_IV_LEN = 16; @@ -100,7 +82,6 @@ public class IpSecManagerTest extends AndroidTestCase { protected void setUp() throws Exception { super.setUp(); mCM = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE); - mISM = (IpSecManager) getContext().getSystemService(Context.IPSEC_SERVICE); } /* @@ -133,19 +114,6 @@ public class IpSecManagerTest extends AndroidTestCase { } } - private static byte[] getKey(int bitLength) { - return Arrays.copyOf(KEY_DATA, bitLength / 8); - } - - private static int getDomain(InetAddress address) { - int domain; - if (address instanceof Inet6Address) - domain = OsConstants.AF_INET6; - else - domain = OsConstants.AF_INET; - return domain; - } - /** This function finds an available port */ private static int findUnusedPort() throws Exception { // Get an available port. @@ -1285,27 +1253,4 @@ public class IpSecManagerTest extends AndroidTestCase { } } } - - private static IpSecTransform buildIpSecTransform( - Context mContext, - IpSecManager.SecurityParameterIndex spi, - IpSecManager.UdpEncapsulationSocket encapSocket, - InetAddress remoteAddr) - throws Exception { - String localAddr = (remoteAddr instanceof Inet4Address) - ? IPV4_LOOPBACK : IPV6_LOOPBACK; - return new IpSecTransform.Builder(mContext) - .setEncryption(new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY)) - .setAuthentication( - new IpSecAlgorithm( - IpSecAlgorithm.AUTH_HMAC_SHA256, - AUTH_KEY, - AUTH_KEY.length * 4)) - .setIpv4Encapsulation(encapSocket, encapSocket.getPort()) - .buildTransportModeTransform(InetAddress.getByName(localAddr), spi); - } - - private static int getPort(FileDescriptor sock) throws Exception { - return ((InetSocketAddress) Os.getsockname(sock)).getPort(); - } } From 60b87e1f6ddda1542233b546885fb3ee137f437e Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 22 Mar 2018 18:47:30 -0700 Subject: [PATCH 3/4] Switch checkTcp and checkUnconnectedUdp to use generic sockets This patch switches IpSecManager checkTransform() tests to use generic sockets, allowing for exercising of Java sockets as well as native/OS sockets. Bug: 76152303 Test: This; ran on Walleye Merged-In: I515227e7aa04c424aefbbe46209ddce81421b2f1 Change-Id: I515227e7aa04c424aefbbe46209ddce81421b2f1 (cherry picked from commit 796f61bb7be36f66302311f89caa74a3a3f13dad) --- .../src/android/net/cts/IpSecManagerTest.java | 108 +++++++----------- 1 file changed, 39 insertions(+), 69 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java index cdbc113c73..9be201b446 100644 --- a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java @@ -27,7 +27,6 @@ import android.net.IpSecAlgorithm; import android.net.IpSecManager; import android.net.IpSecTransform; import android.net.TrafficStats; -import android.os.ParcelFileDescriptor; import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; @@ -38,8 +37,6 @@ import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.Inet6Address; import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.Socket; import java.net.UnknownHostException; import java.util.Arrays; @@ -149,92 +146,65 @@ public class IpSecManagerTest extends IpSecBaseTest { private void checkUnconnectedUdp(IpSecTransform transform, InetAddress local, int sendCount, boolean useJavaSockets) throws Exception { - FileDescriptor udpSocket = null; - int localPort; - + GenericUdpSocket sockLeft = null, sockRight = null; if (useJavaSockets) { - DatagramSocket localSocket = new DatagramSocket(0, local); - localSocket.setSoTimeout(500); - ParcelFileDescriptor pfd = ParcelFileDescriptor.fromDatagramSocket(localSocket); - - localPort = localSocket.getLocalPort(); - udpSocket = pfd.getFileDescriptor(); + SocketPair sockets = getJavaUdpSocketPair(local, mISM, transform, false); + sockLeft = sockets.mLeftSock; + sockRight = sockets.mRightSock; } else { - udpSocket = getBoundUdpSocket(local); - localPort = getPort(udpSocket); + SocketPair sockets = + getNativeUdpSocketPair(local, mISM, transform, false); + sockLeft = sockets.mLeftSock; + sockRight = sockets.mRightSock; } - mISM.applyTransportModeTransform(udpSocket, IpSecManager.DIRECTION_IN, transform); - mISM.applyTransportModeTransform(udpSocket, IpSecManager.DIRECTION_OUT, transform); - for (int i = 0; i < sendCount; i++) { - byte[] in = new byte[TEST_DATA.length]; - Os.sendto(udpSocket, TEST_DATA, 0, TEST_DATA.length, 0, local, localPort); - Os.read(udpSocket, in, 0, in.length); - assertArrayEquals("Encapsulated data did not match.", TEST_DATA, in); + byte[] in; + + sockLeft.sendTo(TEST_DATA, local, sockRight.getPort()); + in = sockRight.receive(); + assertArrayEquals("Left-to-right encrypted data did not match.", TEST_DATA, in); + + sockRight.sendTo(TEST_DATA, local, sockLeft.getPort()); + in = sockLeft.receive(); + assertArrayEquals("Right-to-left encrypted data did not match.", TEST_DATA, in); } - mISM.removeTransportModeTransforms(udpSocket); - Os.close(udpSocket); + sockLeft.close(); + sockRight.close(); } private void checkTcp(IpSecTransform transform, InetAddress local, int sendCount, boolean useJavaSockets) throws Exception { - - FileDescriptor server = null, client = null; - + GenericTcpSocket client = null, accepted = null; if (useJavaSockets) { - Socket serverSocket = new Socket(); - serverSocket.setSoTimeout(500); - ParcelFileDescriptor serverPfd = ParcelFileDescriptor.fromSocket(serverSocket); - server = serverPfd.getFileDescriptor(); - - Socket clientSocket = new Socket(); - clientSocket.setSoTimeout(500); - ParcelFileDescriptor clientPfd = ParcelFileDescriptor.fromSocket(clientSocket); - client = clientPfd.getFileDescriptor(); + SocketPair sockets = getJavaTcpSocketPair(local, mISM, transform); + client = sockets.mLeftSock; + accepted = sockets.mRightSock; } else { - final int domain = getDomain(local); - server = - Os.socket(domain, OsConstants.SOCK_STREAM, IPPROTO_TCP); - client = - Os.socket(domain, OsConstants.SOCK_STREAM, IPPROTO_TCP); + SocketPair sockets = getNativeTcpSocketPair(local, mISM, transform); + client = sockets.mLeftSock; + accepted = sockets.mRightSock; } - Os.bind(server, local, 0); - int port = ((InetSocketAddress) Os.getsockname(server)).getPort(); - - mISM.applyTransportModeTransform(client, IpSecManager.DIRECTION_IN, transform); - mISM.applyTransportModeTransform(client, IpSecManager.DIRECTION_OUT, transform); - mISM.applyTransportModeTransform(server, IpSecManager.DIRECTION_IN, transform); - mISM.applyTransportModeTransform(server, IpSecManager.DIRECTION_OUT, transform); - - Os.listen(server, 10); - Os.connect(client, local, port); - FileDescriptor accepted = Os.accept(server, null); - - mISM.applyTransportModeTransform(accepted, IpSecManager.DIRECTION_IN, transform); - mISM.applyTransportModeTransform(accepted, IpSecManager.DIRECTION_OUT, transform); - // Wait for TCP handshake packets to be counted StatsChecker.waitForNumPackets(3); // (SYN, SYN+ACK, ACK) // Reset StatsChecker, to ignore negotiation overhead. StatsChecker.initStatsChecker(); for (int i = 0; i < sendCount; i++) { - byte[] in = new byte[TEST_DATA.length]; + byte[] in; - Os.write(client, TEST_DATA, 0, TEST_DATA.length); - Os.read(accepted, in, 0, in.length); + client.send(TEST_DATA); + in = accepted.receive(); assertArrayEquals("Client-to-server encrypted data did not match.", TEST_DATA, in); // Allow for newest data + ack packets to be returned before sending next packet // Also add the number of expected packets in each of the previous runs (4 per run) StatsChecker.waitForNumPackets(2 + (4 * i)); - in = new byte[TEST_DATA.length]; - Os.write(accepted, TEST_DATA, 0, TEST_DATA.length); - Os.read(client, in, 0, in.length); + accepted.send(TEST_DATA); + in = client.receive(); assertArrayEquals("Server-to-client encrypted data did not match.", TEST_DATA, in); // Allow for all data + ack packets to be returned before sending next packet @@ -254,9 +224,8 @@ public class IpSecManagerTest extends IpSecBaseTest { // Socket or FileDescriptor flavors of applyTransportModeTransform() in IpSecManager // for more details. - Os.close(server); - Os.close(client); - Os.close(accepted); + client.close(); + accepted.close(); } /* @@ -572,16 +541,17 @@ public class IpSecManagerTest extends IpSecBaseTest { int expectedInnerBytes = innerPacketSize * sendCount; int expectedPackets = sendCount; + // Each run sends two packets, one in each direction. + sendCount *= 2; + expectedOuterBytes *= 2; + expectedInnerBytes *= 2; + expectedPackets *= 2; + // Add TCP ACKs for data packets if (protocol == IPPROTO_TCP) { int encryptedTcpPktSize = calculateEspPacketSize(TCP_HDRLEN_WITH_OPTIONS, ivLen, blkSize, truncLenBits); - // Each run sends two packets, one in each direction. - sendCount *= 2; - expectedOuterBytes *= 2; - expectedInnerBytes *= 2; - expectedPackets *= 2; // Add data packet ACKs expectedOuterBytes += (encryptedTcpPktSize + udpEncapLen + ipHdrLen) * (sendCount); From b9b074bc037e95e404f9406377fe025c25f67450 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 27 Mar 2018 21:33:31 -0700 Subject: [PATCH 4/4] Prevent CTS from hanging if no UDP packet was received Previously, CTS tests could block forever on attempting to read a packet from a UDP socket. This patch modifies the receive methods of the NativeUdpSocket wrapper, allowing it to gracefully fail if UDP packets are not received. This patch also updates the IKE over UDP encap socket test to use the NativeUdpSocket wrapper, preventing the tests from hanging in the same fashion. Bug: 70938121 Test: Ran updated tests on walleye + marlin Merged-In: I390e4585e85647eb8555e706d44b76f95dec931f Change-Id: I390e4585e85647eb8555e706d44b76f95dec931f (cherry picked from commit e2fcb9d64ba10f07a69a6b96a7f7e1465856172a) --- .../src/android/net/cts/IpSecBaseTest.java | 31 ++- .../src/android/net/cts/IpSecManagerTest.java | 201 +++++------------- 2 files changed, 80 insertions(+), 152 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/IpSecBaseTest.java b/tests/cts/net/src/android/net/cts/IpSecBaseTest.java index 57cfe2a9e9..7132ecf685 100644 --- a/tests/cts/net/src/android/net/cts/IpSecBaseTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecBaseTest.java @@ -25,6 +25,7 @@ import android.net.IpSecTransform; import android.system.Os; import android.system.OsConstants; import android.test.AndroidTestCase; +import android.util.Log; import java.io.FileDescriptor; import java.io.IOException; @@ -38,6 +39,7 @@ import java.net.ServerSocket; import java.net.Socket; import java.net.SocketException; import java.util.Arrays; +import java.util.concurrent.atomic.AtomicInteger; public class IpSecBaseTest extends AndroidTestCase { @@ -51,6 +53,7 @@ public class IpSecBaseTest extends AndroidTestCase { protected static final byte[] TEST_DATA = "Best test data ever!".getBytes(); protected static final int DATA_BUFFER_LEN = 4096; + protected static final int SOCK_TIMEOUT = 500; private static final byte[] KEY_DATA = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, @@ -124,9 +127,27 @@ public class IpSecBaseTest extends AndroidTestCase { @Override public byte[] receive() throws Exception { byte[] in = new byte[DATA_BUFFER_LEN]; - int bytesRead = Os.read(mFd, in, 0, DATA_BUFFER_LEN); + AtomicInteger bytesRead = new AtomicInteger(-1); - return Arrays.copyOfRange(in, 0, bytesRead); + Thread readSockThread = new Thread(() -> { + long startTime = System.currentTimeMillis(); + while (bytesRead.get() < 0 && System.currentTimeMillis() < startTime + SOCK_TIMEOUT) { + try { + bytesRead.set(Os.recvfrom(mFd, in, 0, DATA_BUFFER_LEN, 0, null)); + } catch (Exception e) { + Log.e(TAG, "Error encountered reading from socket", e); + } + } + }); + + readSockThread.start(); + readSockThread.join(SOCK_TIMEOUT); + + if (bytesRead.get() < 0) { + throw new IOException("No data received from socket"); + } + + return Arrays.copyOfRange(in, 0, bytesRead.get()); } @Override @@ -174,7 +195,7 @@ public class IpSecBaseTest extends AndroidTestCase { public JavaUdpSocket(InetAddress localAddr) { try { mSocket = new DatagramSocket(0, localAddr); - mSocket.setSoTimeout(500); + mSocket.setSoTimeout(SOCK_TIMEOUT); } catch (SocketException e) { // Fail loudly if we can't set up sockets properly. And without the timeout, we // could easily end up in an endless wait. @@ -227,7 +248,7 @@ public class IpSecBaseTest extends AndroidTestCase { public JavaTcpSocket(Socket socket) { mSocket = socket; try { - mSocket.setSoTimeout(500); + mSocket.setSoTimeout(SOCK_TIMEOUT); } catch (SocketException e) { // Fail loudly if we can't set up sockets properly. And without the timeout, we // could easily end up in an endless wait. @@ -279,7 +300,7 @@ public class IpSecBaseTest extends AndroidTestCase { } } - private static void applyTransformBidirectionally( + protected static void applyTransformBidirectionally( IpSecManager ism, IpSecTransform transform, GenericSocket socket) throws Exception { for (int direction : DIRECTIONS) { socket.applyTransportModeTransform(ism, direction, transform); diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java index 9be201b446..95d91a25b8 100644 --- a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java @@ -576,34 +576,68 @@ public class IpSecManagerTest extends IpSecBaseTest { } } - public void testIkeOverUdpEncapSocket() throws Exception { - // IPv6 not supported for UDP-encap-ESP - InetAddress local = InetAddress.getByName(IPV4_LOOPBACK); + private void checkIkePacket( + NativeUdpSocket wrappedEncapSocket, InetAddress localAddr) throws Exception { StatsChecker.initStatsChecker(); - try (IpSecManager.UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket()) { - int localPort = getPort(encapSocket.getFileDescriptor()); + try (NativeUdpSocket remoteSocket = new NativeUdpSocket(getBoundUdpSocket(localAddr))) { - // Append ESP header - 4 bytes of SPI, 4 bytes of seq number + // Append IKE/ESP header - 4 bytes of SPI, 4 bytes of seq number, all zeroed out + // If the first four bytes are zero, assume non-ESP (IKE traffic) byte[] dataWithEspHeader = new byte[TEST_DATA.length + 8]; System.arraycopy(TEST_DATA, 0, dataWithEspHeader, 8, TEST_DATA.length); - byte[] in = new byte[dataWithEspHeader.length]; - Os.sendto( - encapSocket.getFileDescriptor(), - dataWithEspHeader, - 0, - dataWithEspHeader.length, - 0, - local, - localPort); - Os.read(encapSocket.getFileDescriptor(), in, 0, in.length); + // Send the IKE packet from remoteSocket to wrappedEncapSocket. Since IKE packets + // are multiplexed over the socket, we expect them to appear on the encap socket + // (as opposed to being decrypted and received on the non-encap socket) + remoteSocket.sendTo(dataWithEspHeader, localAddr, wrappedEncapSocket.getPort()); + byte[] in = wrappedEncapSocket.receive(); assertArrayEquals("Encapsulated data did not match.", dataWithEspHeader, in); - int ipHdrLen = local instanceof Inet6Address ? IP6_HDRLEN : IP4_HDRLEN; - int expectedPacketSize = dataWithEspHeader.length + UDP_HDRLEN + ipHdrLen; - StatsChecker.assertUidStatsDelta(expectedPacketSize, 1, expectedPacketSize, 1); - StatsChecker.assertIfaceStatsDelta(expectedPacketSize, 1, expectedPacketSize, 1); + // Also test that the IKE socket can send data out. + wrappedEncapSocket.sendTo(dataWithEspHeader, localAddr, remoteSocket.getPort()); + in = remoteSocket.receive(); + assertArrayEquals("Encapsulated data did not match.", dataWithEspHeader, in); + + // Calculate expected packet sizes. Always use IPv4 header, since our kernels only + // guarantee support of UDP encap on IPv4. + int expectedNumPkts = 2; + int expectedPacketSize = + expectedNumPkts * (dataWithEspHeader.length + UDP_HDRLEN + IP4_HDRLEN); + + StatsChecker.waitForNumPackets(expectedNumPkts); + StatsChecker.assertUidStatsDelta( + expectedPacketSize, expectedNumPkts, expectedPacketSize, expectedNumPkts); + StatsChecker.assertIfaceStatsDelta( + expectedPacketSize, expectedNumPkts, expectedPacketSize, expectedNumPkts); + } + } + + public void testIkeOverUdpEncapSocket() throws Exception { + // IPv6 not supported for UDP-encap-ESP + InetAddress local = InetAddress.getByName(IPV4_LOOPBACK); + try (IpSecManager.UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket()) { + NativeUdpSocket wrappedEncapSocket = + new NativeUdpSocket(encapSocket.getFileDescriptor()); + checkIkePacket(wrappedEncapSocket, local); + + // Now try with a transform applied to a socket using this Encap socket + IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); + + try (IpSecManager.SecurityParameterIndex spi = + mISM.allocateSecurityParameterIndex(local); + IpSecTransform transform = + new IpSecTransform.Builder(mContext) + .setEncryption(crypt) + .setAuthentication(auth) + .setIpv4Encapsulation(encapSocket, encapSocket.getPort()) + .buildTransportModeTransform(local, spi); + JavaUdpSocket localSocket = new JavaUdpSocket(local)) { + applyTransformBidirectionally(mISM, transform, localSocket); + + checkIkePacket(wrappedEncapSocket, local); + } } } @@ -1096,131 +1130,4 @@ public class IpSecManagerTest extends IpSecBaseTest { assertTrue("Returned invalid port", encapSocket.getPort() != 0); } } - - public void testUdpEncapsulation() throws Exception { - InetAddress local = InetAddress.getByName(IPV4_LOOPBACK); - - // TODO: Refactor to make this more representative of a normal application use case. (use - // separate sockets for inbound and outbound) - // Create SPIs, UDP encap socket - try (IpSecManager.UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket(); - IpSecManager.SecurityParameterIndex spi = - mISM.allocateSecurityParameterIndex(local); - IpSecTransform transform = - buildIpSecTransform(mContext, spi, encapSocket, local)) { - - // Create user socket, apply transform to it - FileDescriptor udpSocket = null; - try { - udpSocket = getBoundUdpSocket(local); - int port = getPort(udpSocket); - - mISM.applyTransportModeTransform( - udpSocket, IpSecManager.DIRECTION_IN, transform); - mISM.applyTransportModeTransform( - udpSocket, IpSecManager.DIRECTION_OUT, transform); - - // Send an ESP packet from this socket to itself. Since the inbound and - // outbound transforms match, we should receive the data we sent. - byte[] data = new String("IPSec UDP-encap-ESP test data").getBytes("UTF-8"); - Os.sendto(udpSocket, data, 0, data.length, 0, local, port); - byte[] in = new byte[data.length]; - Os.read(udpSocket, in, 0, in.length); - assertTrue("Encapsulated data did not match.", Arrays.equals(data, in)); - - // Send an IKE packet from this socket to itself. IKE packets (SPI of 0) - // are not transformed in any way, and should be sent in the clear - // We expect this to work too (no inbound transforms) - final byte[] header = new byte[] {0, 0, 0, 0}; - final String message = "Sample IKE Packet"; - data = (new String(header) + message).getBytes("UTF-8"); - Os.sendto( - encapSocket.getFileDescriptor(), - data, - 0, - data.length, - 0, - local, - encapSocket.getPort()); - in = new byte[data.length]; - Os.read(encapSocket.getFileDescriptor(), in, 0, in.length); - assertTrue( - "Encap socket was unable to send/receive IKE data", - Arrays.equals(data, in)); - - mISM.removeTransportModeTransforms(udpSocket); - } finally { - if (udpSocket != null) { - Os.close(udpSocket); - } - } - } - } - - public void testIke() throws Exception { - InetAddress localAddr = InetAddress.getByName(IPV4_LOOPBACK); - - // TODO: Refactor to make this more representative of a normal application use case. (use - // separate sockets for inbound and outbound) - try (IpSecManager.UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket(); - IpSecManager.SecurityParameterIndex spi = - mISM.allocateSecurityParameterIndex(localAddr); - IpSecTransform transform = - buildIpSecTransform(mContext, spi, encapSocket, localAddr)) { - - // Create user socket, apply transform to it - FileDescriptor sock = null; - - try { - sock = getBoundUdpSocket(localAddr); - int port = getPort(sock); - - mISM.applyTransportModeTransform(sock, IpSecManager.DIRECTION_IN, transform); - mISM.applyTransportModeTransform(sock, IpSecManager.DIRECTION_OUT, transform); - - // TODO: Find a way to set a timeout on the socket, and assert the ESP packet - // doesn't make it through. Setting sockopts currently throws EPERM (possibly - // because it is owned by a different UID). - - // Send ESP packet from our socket to the encap socket. The SPIs do not - // match, and we should expect this packet to be dropped. - byte[] header = new byte[] {1, 1, 1, 1}; - String message = "Sample ESP Packet"; - byte[] data = (new String(header) + message).getBytes("UTF-8"); - Os.sendto(sock, data, 0, data.length, 0, localAddr, encapSocket.getPort()); - - // Send IKE packet from the encap socket to itself. Since IKE is not - // transformed in any way, this should succeed. - header = new byte[] {0, 0, 0, 0}; - message = "Sample IKE Packet"; - data = (new String(header) + message).getBytes("UTF-8"); - Os.sendto( - encapSocket.getFileDescriptor(), - data, - 0, - data.length, - 0, - localAddr, - encapSocket.getPort()); - - // ESP data should be dropped, due to different input SPI (as opposed to being - // readable from the encapSocket) - // Thus, only IKE data should be received from the socket. - // If the first four bytes are zero, assume non-ESP (IKE) traffic. - // Expect an nulled out SPI just as we sent out, without being modified. - byte[] in = new byte[4]; - in[0] = 1; // Make sure the array has to be overwritten to pass - Os.read(encapSocket.getFileDescriptor(), in, 0, in.length); - assertTrue( - "Encap socket received UDP-encap-ESP data despite invalid SPIs", - Arrays.equals(header, in)); - - mISM.removeTransportModeTransforms(sock); - } finally { - if (sock != null) { - Os.close(sock); - } - } - } - } }