diff options
author | android-build-team Robot <android-build-team-robot@google.com> | 2019-11-11 21:19:18 +0000 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2019-11-11 21:19:18 +0000 |
commit | db74d7937f3a9503f0e2590ec24c3bcfbf259ce0 (patch) | |
tree | b39c3e794945072d38b97c963c5a6f10753514e1 /tests/iketests/src/java/android | |
parent | 7ffef5cae6d3c93c93b4055fd22517d44f77acda (diff) | |
parent | eb4c77d7228f956f928c7d3500a220339ee78388 (diff) | |
download | ike-db74d7937f3a9503f0e2590ec24c3bcfbf259ce0.tar.gz |
Snap for 6001391 from eb4c77d7228f956f928c7d3500a220339ee78388 to qt-aml-tzdata-release
Change-Id: Ic6fc3b152696e0096d00036f460262a8b0319394
Diffstat (limited to 'tests/iketests/src/java/android')
9 files changed, 1673 insertions, 0 deletions
diff --git a/tests/iketests/src/java/android/net/eap/EapSessionConfigTest.java b/tests/iketests/src/java/android/net/eap/EapSessionConfigTest.java new file mode 100644 index 00000000..eed32e3e --- /dev/null +++ b/tests/iketests/src/java/android/net/eap/EapSessionConfigTest.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.eap; + +import static android.net.eap.EapSessionConfig.DEFAULT_IDENTITY; +import static android.telephony.TelephonyManager.APPTYPE_USIM; + +import static com.android.internal.net.eap.message.EapData.EAP_TYPE_AKA; +import static com.android.internal.net.eap.message.EapData.EAP_TYPE_AKA_PRIME; +import static com.android.internal.net.eap.message.EapData.EAP_TYPE_MSCHAP_V2; +import static com.android.internal.net.eap.message.EapData.EAP_TYPE_SIM; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import android.net.eap.EapSessionConfig.EapAkaConfig; +import android.net.eap.EapSessionConfig.EapAkaPrimeConfig; +import android.net.eap.EapSessionConfig.EapMethodConfig; +import android.net.eap.EapSessionConfig.EapMsChapV2Config; +import android.net.eap.EapSessionConfig.EapSimConfig; + +import org.junit.Test; + +import java.nio.charset.StandardCharsets; + +public class EapSessionConfigTest { + private static final byte[] EAP_IDENTITY = + "test@android.net".getBytes(StandardCharsets.US_ASCII); + private static final int SUB_ID = 1; + private static final String NETWORK_NAME = "android.net"; + private static final boolean ALLOW_MISMATCHED_NETWORK_NAMES = true; + private static final String USERNAME = "username"; + private static final String PASSWORD = "password"; + + @Test + public void testBuildEapSim() { + EapSessionConfig result = new EapSessionConfig.Builder() + .setEapIdentity(EAP_IDENTITY) + .setEapSimConfig(SUB_ID, APPTYPE_USIM) + .build(); + + assertArrayEquals(EAP_IDENTITY, result.eapIdentity); + + EapMethodConfig eapMethodConfig = result.eapConfigs.get(EAP_TYPE_SIM); + assertEquals(EAP_TYPE_SIM, eapMethodConfig.methodType); + EapSimConfig eapSimConfig = (EapSimConfig) eapMethodConfig; + assertEquals(SUB_ID, eapSimConfig.subId); + assertEquals(APPTYPE_USIM, eapSimConfig.apptype); + } + + @Test + public void testBuildEapAka() { + EapSessionConfig result = new EapSessionConfig.Builder() + .setEapAkaConfig(SUB_ID, APPTYPE_USIM) + .build(); + + assertArrayEquals(DEFAULT_IDENTITY, result.eapIdentity); + EapMethodConfig eapMethodConfig = result.eapConfigs.get(EAP_TYPE_AKA); + EapAkaConfig eapAkaConfig = (EapAkaConfig) eapMethodConfig; + assertEquals(SUB_ID, eapAkaConfig.subId); + assertEquals(APPTYPE_USIM, eapAkaConfig.apptype); + } + + @Test + public void testBuildEapAkaPrime() { + EapSessionConfig result = + new EapSessionConfig.Builder() + .setEapAkaPrimeConfig( + SUB_ID, APPTYPE_USIM, NETWORK_NAME, ALLOW_MISMATCHED_NETWORK_NAMES) + .build(); + + assertEquals(DEFAULT_IDENTITY, result.eapIdentity); + EapMethodConfig eapMethodConfig = result.eapConfigs.get(EAP_TYPE_AKA_PRIME); + EapAkaPrimeConfig eapAkaPrimeConfig = (EapAkaPrimeConfig) eapMethodConfig; + assertEquals(SUB_ID, eapAkaPrimeConfig.subId); + assertEquals(APPTYPE_USIM, eapAkaPrimeConfig.apptype); + assertEquals(NETWORK_NAME, eapAkaPrimeConfig.networkName); + assertTrue(eapAkaPrimeConfig.allowMismatchedNetworkNames); + } + + @Test + public void testBuildEapMsChapV2() { + EapSessionConfig result = + new EapSessionConfig.Builder().setEapMsChapV2Config(USERNAME, PASSWORD).build(); + + EapMsChapV2Config config = (EapMsChapV2Config) result.eapConfigs.get(EAP_TYPE_MSCHAP_V2); + assertEquals(USERNAME, config.username); + assertEquals(PASSWORD, config.password); + } + + @Test + public void testBuildWithoutConfigs() { + try { + new EapSessionConfig.Builder().build(); + fail("build() should throw an IllegalStateException if no EAP methods are configured"); + } catch (IllegalStateException expected) { + } + } +} diff --git a/tests/iketests/src/java/android/net/ipsec/ike/ChildSessionConfigurationTest.java b/tests/iketests/src/java/android/net/ipsec/ike/ChildSessionConfigurationTest.java new file mode 100644 index 00000000..08d89942 --- /dev/null +++ b/tests/iketests/src/java/android/net/ipsec/ike/ChildSessionConfigurationTest.java @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.ipsec.ike; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; + +import android.net.LinkAddress; + +import com.android.internal.net.ipsec.ike.message.IkeConfigPayload; +import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttribute; +import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv4Address; +import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv4Netmask; +import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv6Address; + +import libcore.net.InetAddressUtils; + +import org.junit.Before; +import org.junit.Test; + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.util.LinkedList; +import java.util.List; + +public final class ChildSessionConfigurationTest { + private static final int IP4_PREFIX_LEN = 28; + private static final Inet4Address IPV4_ADDRESS = + (Inet4Address) (InetAddressUtils.parseNumericAddress("192.0.2.100")); + private static final Inet4Address IPV4_NETMASK = + (Inet4Address) (InetAddressUtils.parseNumericAddress("255.255.255.240")); + private static final LinkAddress IPV4_LINK_ADDRESS = + new LinkAddress(IPV4_ADDRESS, IP4_PREFIX_LEN); + + private static final int IP6_PREFIX_LEN = 64; + private static final Inet6Address IPV6_ADDRESS = + (Inet6Address) (InetAddressUtils.parseNumericAddress("2001:db8::1")); + private static final LinkAddress IPV6_LINK_ADDRESS = + new LinkAddress(IPV6_ADDRESS, IP6_PREFIX_LEN); + + private List mMockInTsList; + private List mMockOutTsList; + + private ConfigAttributeIpv4Address mIpv4Attr; + private ConfigAttributeIpv4Netmask mNetmaskAttr; + private ConfigAttributeIpv6Address mIpv6Attr; + + @Before + public void setUp() throws Exception { + mMockInTsList = new LinkedList<IkeTrafficSelector>(); + mMockInTsList.add(mock(IkeTrafficSelector.class)); + + mMockOutTsList = new LinkedList<IkeTrafficSelector>(); + mMockOutTsList.add(mock(IkeTrafficSelector.class)); + mMockOutTsList.add(mock(IkeTrafficSelector.class)); + + mIpv4Attr = new ConfigAttributeIpv4Address(IPV4_ADDRESS); + mNetmaskAttr = new ConfigAttributeIpv4Netmask(IPV4_NETMASK.getAddress()); + mIpv6Attr = new ConfigAttributeIpv6Address(IPV6_LINK_ADDRESS); + } + + private void verifySessionConfigCommon(ChildSessionConfiguration sessionConfig) { + verifyTsList(mMockInTsList, sessionConfig.getInboundTrafficSelectors()); + verifyTsList(mMockOutTsList, sessionConfig.getOutboundTrafficSelectors()); + } + + private void verifyTsList( + List<IkeTrafficSelector> expectedList, List<IkeTrafficSelector> tsList) { + assertEquals(expectedList.size(), tsList.size()); + for (int i = 0; i < expectedList.size(); i++) { + assertEquals(expectedList.get(i), tsList.get(i)); + } + } + + @Test + public void testBuildWithoutConfig() { + ChildSessionConfiguration sessionConfig = + new ChildSessionConfiguration(mMockInTsList, mMockOutTsList); + + verifySessionConfigCommon(sessionConfig); + } + + @Test + public void testBuildWithNetmaskAttr() { + List<ConfigAttribute> attributeList = new LinkedList<>(); + attributeList.add(mIpv4Attr); + attributeList.add(mNetmaskAttr); + attributeList.add(mIpv6Attr); + + IkeConfigPayload configPayload = new IkeConfigPayload(true /*isReply*/, attributeList); + + ChildSessionConfiguration sessionConfig = + new ChildSessionConfiguration(mMockInTsList, mMockOutTsList, configPayload); + + verifySessionConfigCommon(sessionConfig); + + List<LinkAddress> expectedInternalAddrList = new LinkedList<>(); + expectedInternalAddrList.add(IPV4_LINK_ADDRESS); + expectedInternalAddrList.add(IPV6_LINK_ADDRESS); + + assertEquals( + expectedInternalAddrList.size(), sessionConfig.getInternalAddressList().size()); + for (int i = 0; i < expectedInternalAddrList.size(); i++) { + assertEquals( + expectedInternalAddrList.get(i), sessionConfig.getInternalAddressList().get(i)); + } + } + + @Test + public void testBuildWithoutNetmaskAttr() { + List<ConfigAttribute> attributeList = new LinkedList<>(); + attributeList.add(mIpv4Attr); + attributeList.add(mIpv6Attr); + + IkeConfigPayload configPayload = new IkeConfigPayload(true /*isReply*/, attributeList); + + ChildSessionConfiguration sessionConfig = + new ChildSessionConfiguration(mMockInTsList, mMockOutTsList, configPayload); + + verifySessionConfigCommon(sessionConfig); + + List<LinkAddress> expectedInternalAddrList = new LinkedList<>(); + expectedInternalAddrList.add(new LinkAddress(IPV4_ADDRESS, 32)); + expectedInternalAddrList.add(IPV6_LINK_ADDRESS); + + assertEquals( + expectedInternalAddrList.size(), sessionConfig.getInternalAddressList().size()); + for (int i = 0; i < expectedInternalAddrList.size(); i++) { + assertEquals( + expectedInternalAddrList.get(i), sessionConfig.getInternalAddressList().get(i)); + } + } + + @Test + public void testBuildWithConfigReq() { + List<ConfigAttribute> attributeList = new LinkedList<>(); + attributeList.add(mIpv4Attr); + attributeList.add(mIpv6Attr); + + IkeConfigPayload configPayload = new IkeConfigPayload(false /*isReply*/, attributeList); + + try { + new ChildSessionConfiguration(mMockInTsList, mMockOutTsList, configPayload); + fail("Expected to fail because provided config paylaod is not a reply."); + } catch (IllegalArgumentException expected) { + + } + } +} diff --git a/tests/iketests/src/java/android/net/ipsec/ike/ChildSessionOptionsTest.java b/tests/iketests/src/java/android/net/ipsec/ike/ChildSessionOptionsTest.java new file mode 100644 index 00000000..242957d6 --- /dev/null +++ b/tests/iketests/src/java/android/net/ipsec/ike/ChildSessionOptionsTest.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.ipsec.ike; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.fail; + +import org.junit.Test; + +public final class ChildSessionOptionsTest { + private static final int NUM_TS = 1; + + @Test + public void testBuild() throws Exception { + ChildSaProposal saProposal = + new ChildSaProposal.Builder() + .addEncryptionAlgorithm( + SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12, + SaProposal.KEY_LEN_AES_128) + .build(); + ChildSessionOptions sessionOptions = + new TunnelModeChildSessionOptions.Builder().addSaProposal(saProposal).build(); + + assertArrayEquals(new SaProposal[] {saProposal}, sessionOptions.getSaProposals()); + assertEquals(NUM_TS, sessionOptions.getLocalTrafficSelectors().length); + assertEquals(NUM_TS, sessionOptions.getRemoteTrafficSelectors().length); + assertFalse(sessionOptions.isTransportMode()); + } + + @Test + public void testBuildWithoutSaProposal() throws Exception { + try { + new TunnelModeChildSessionOptions.Builder().build(); + fail("Expected to fail due to the absence of SA proposal."); + } catch (IllegalArgumentException expected) { + } + } +} diff --git a/tests/iketests/src/java/android/net/ipsec/ike/IkeSessionOptionsTest.java b/tests/iketests/src/java/android/net/ipsec/ike/IkeSessionOptionsTest.java new file mode 100644 index 00000000..fa077d17 --- /dev/null +++ b/tests/iketests/src/java/android/net/ipsec/ike/IkeSessionOptionsTest.java @@ -0,0 +1,258 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.ipsec.ike; + +import static android.net.ipsec.ike.IkeSessionOptions.IkeAuthConfig; +import static android.net.ipsec.ike.IkeSessionOptions.IkeAuthDigitalSignLocalConfig; +import static android.net.ipsec.ike.IkeSessionOptions.IkeAuthDigitalSignRemoteConfig; +import static android.net.ipsec.ike.IkeSessionOptions.IkeAuthEapConfig; +import static android.net.ipsec.ike.IkeSessionOptions.IkeAuthPskConfig; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; + +import android.content.Context; +import android.net.IpSecManager; +import android.net.IpSecManager.UdpEncapsulationSocket; +import android.net.eap.EapSessionConfig; + +import androidx.test.InstrumentationRegistry; + +import com.android.internal.net.TestUtils; + +import libcore.net.InetAddressUtils; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.net.Inet4Address; +import java.security.PrivateKey; +import java.security.cert.X509Certificate; +import java.security.interfaces.DSAPrivateKey; +import java.security.interfaces.RSAPrivateKey; + +public final class IkeSessionOptionsTest { + private static final String PSK_HEX_STRING = "6A756E69706572313233"; + private static final byte[] PSK = TestUtils.hexStringToByteArray(PSK_HEX_STRING); + + private static final Inet4Address LOCAL_IPV4_ADDRESS = + (Inet4Address) (InetAddressUtils.parseNumericAddress("192.0.2.200")); + private static final Inet4Address REMOTE_IPV4_ADDRESS = + (Inet4Address) (InetAddressUtils.parseNumericAddress("192.0.2.100")); + + private UdpEncapsulationSocket mUdpEncapSocket; + private IkeSaProposal mIkeSaProposal; + private IkeIdentification mLocalIdentification; + private IkeIdentification mRemoteIdentification; + + private X509Certificate mMockServerCaCert; + private X509Certificate mMockClientEndCert; + private PrivateKey mMockRsaPrivateKey; + + @Before + public void setUp() throws Exception { + Context context = InstrumentationRegistry.getContext(); + IpSecManager ipSecManager = (IpSecManager) context.getSystemService(Context.IPSEC_SERVICE); + mUdpEncapSocket = ipSecManager.openUdpEncapsulationSocket(); + + mIkeSaProposal = + new IkeSaProposal.Builder() + .addEncryptionAlgorithm( + SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8, + SaProposal.KEY_LEN_AES_128) + .addPseudorandomFunction(SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC) + .addDhGroup(SaProposal.DH_GROUP_1024_BIT_MODP) + .build(); + mLocalIdentification = new IkeIpv4AddrIdentification(LOCAL_IPV4_ADDRESS); + mRemoteIdentification = new IkeIpv4AddrIdentification(REMOTE_IPV4_ADDRESS); + + mMockServerCaCert = mock(X509Certificate.class); + mMockClientEndCert = mock(X509Certificate.class); + mMockRsaPrivateKey = mock(RSAPrivateKey.class); + } + + @After + public void tearDown() throws Exception { + mUdpEncapSocket.close(); + } + + private void verifyIkeSessionOptionsCommon(IkeSessionOptions sessionOptions) { + assertEquals(REMOTE_IPV4_ADDRESS, sessionOptions.getServerAddress()); + assertEquals(mUdpEncapSocket, sessionOptions.getUdpEncapsulationSocket()); + assertArrayEquals(new SaProposal[] {mIkeSaProposal}, sessionOptions.getSaProposals()); + + assertEquals(mLocalIdentification, sessionOptions.getLocalIdentification()); + assertEquals(mRemoteIdentification, sessionOptions.getRemoteIdentification()); + + assertFalse(sessionOptions.isIkeFragmentationSupported()); + } + + @Test + public void testBuildWithPsk() throws Exception { + IkeSessionOptions sessionOptions = + new IkeSessionOptions.Builder() + .setServerAddress(REMOTE_IPV4_ADDRESS) + .setUdpEncapsulationSocket(mUdpEncapSocket) + .addSaProposal(mIkeSaProposal) + .setLocalIdentification(mLocalIdentification) + .setRemoteIdentification(mRemoteIdentification) + .setAuthPsk(PSK) + .build(); + + verifyIkeSessionOptionsCommon(sessionOptions); + + IkeAuthConfig localConfig = sessionOptions.getLocalAuthConfig(); + assertTrue(localConfig instanceof IkeAuthPskConfig); + assertEquals(IkeSessionOptions.IKE_AUTH_METHOD_PSK, localConfig.mAuthMethod); + assertArrayEquals(PSK, ((IkeAuthPskConfig) localConfig).mPsk); + + IkeAuthConfig remoteConfig = sessionOptions.getRemoteAuthConfig(); + assertTrue(remoteConfig instanceof IkeAuthPskConfig); + assertEquals(IkeSessionOptions.IKE_AUTH_METHOD_PSK, remoteConfig.mAuthMethod); + assertArrayEquals(PSK, ((IkeAuthPskConfig) remoteConfig).mPsk); + } + + @Test + public void testBuildWithEap() throws Exception { + EapSessionConfig eapConfig = mock(EapSessionConfig.class); + + IkeSessionOptions sessionOptions = + new IkeSessionOptions.Builder() + .setServerAddress(REMOTE_IPV4_ADDRESS) + .setUdpEncapsulationSocket(mUdpEncapSocket) + .addSaProposal(mIkeSaProposal) + .setLocalIdentification(mLocalIdentification) + .setRemoteIdentification(mRemoteIdentification) + .setAuthEap(mMockServerCaCert, eapConfig) + .build(); + + verifyIkeSessionOptionsCommon(sessionOptions); + + IkeAuthConfig localConfig = sessionOptions.getLocalAuthConfig(); + assertTrue(localConfig instanceof IkeAuthEapConfig); + assertEquals(IkeSessionOptions.IKE_AUTH_METHOD_EAP, localConfig.mAuthMethod); + assertEquals(eapConfig, ((IkeAuthEapConfig) localConfig).mEapConfig); + + IkeAuthConfig remoteConfig = sessionOptions.getRemoteAuthConfig(); + assertTrue(remoteConfig instanceof IkeAuthDigitalSignRemoteConfig); + assertEquals(IkeSessionOptions.IKE_AUTH_METHOD_PUB_KEY_SIGNATURE, remoteConfig.mAuthMethod); + assertEquals( + mMockServerCaCert, + ((IkeAuthDigitalSignRemoteConfig) remoteConfig).mTrustAnchor.getTrustedCert()); + } + + @Test + public void testBuildWithDigitalSignatureAuth() throws Exception { + IkeSessionOptions sessionOptions = + new IkeSessionOptions.Builder() + .setServerAddress(REMOTE_IPV4_ADDRESS) + .setUdpEncapsulationSocket(mUdpEncapSocket) + .addSaProposal(mIkeSaProposal) + .setLocalIdentification(mLocalIdentification) + .setRemoteIdentification(mRemoteIdentification) + .setAuthDigitalSignature( + mMockServerCaCert, mMockClientEndCert, mMockRsaPrivateKey) + .build(); + + verifyIkeSessionOptionsCommon(sessionOptions); + + IkeAuthConfig localConfig = sessionOptions.getLocalAuthConfig(); + assertTrue(localConfig instanceof IkeAuthDigitalSignLocalConfig); + + IkeAuthDigitalSignLocalConfig localAuthConfig = (IkeAuthDigitalSignLocalConfig) localConfig; + assertEquals( + IkeSessionOptions.IKE_AUTH_METHOD_PUB_KEY_SIGNATURE, localAuthConfig.mAuthMethod); + assertEquals(mMockClientEndCert, localAuthConfig.mEndCert); + assertTrue(localAuthConfig.mIntermediateCerts.isEmpty()); + assertEquals(mMockRsaPrivateKey, localAuthConfig.mPrivateKey); + + IkeAuthConfig remoteConfig = sessionOptions.getRemoteAuthConfig(); + assertTrue(remoteConfig instanceof IkeAuthDigitalSignRemoteConfig); + assertEquals(IkeSessionOptions.IKE_AUTH_METHOD_PUB_KEY_SIGNATURE, remoteConfig.mAuthMethod); + assertEquals( + mMockServerCaCert, + ((IkeAuthDigitalSignRemoteConfig) remoteConfig).mTrustAnchor.getTrustedCert()); + } + + @Test + public void testBuildWithDsaDigitalSignatureAuth() throws Exception { + try { + IkeSessionOptions sessionOptions = + new IkeSessionOptions.Builder() + .setServerAddress(REMOTE_IPV4_ADDRESS) + .setUdpEncapsulationSocket(mUdpEncapSocket) + .addSaProposal(mIkeSaProposal) + .setLocalIdentification(mLocalIdentification) + .setRemoteIdentification(mRemoteIdentification) + .setAuthDigitalSignature( + mMockServerCaCert, + mMockClientEndCert, + mock(DSAPrivateKey.class)) + .build(); + fail("Expected to fail because DSA is not supported"); + } catch (IllegalArgumentException expected) { + + } + } + + @Test + public void testBuildWithoutSaProposal() throws Exception { + try { + new IkeSessionOptions.Builder() + .setServerAddress(REMOTE_IPV4_ADDRESS) + .setUdpEncapsulationSocket(mUdpEncapSocket) + .build(); + fail("Expected to fail due to absence of SA proposal."); + } catch (IllegalArgumentException expected) { + } + } + + @Test + public void testBuildWithoutLocalId() throws Exception { + try { + new IkeSessionOptions.Builder() + .setServerAddress(REMOTE_IPV4_ADDRESS) + .setUdpEncapsulationSocket(mUdpEncapSocket) + .addSaProposal(mIkeSaProposal) + .setRemoteIdentification(mRemoteIdentification) + .setAuthPsk(PSK) + .build(); + fail("Expected to fail because local identification is not set."); + } catch (IllegalArgumentException expected) { + } + } + + @Test + public void testBuildWithoutSetAuth() throws Exception { + try { + new IkeSessionOptions.Builder() + .setServerAddress(REMOTE_IPV4_ADDRESS) + .setUdpEncapsulationSocket(mUdpEncapSocket) + .addSaProposal(mIkeSaProposal) + .setLocalIdentification(mLocalIdentification) + .setRemoteIdentification(mRemoteIdentification) + .build(); + fail("Expected to fail because authentiction method is not set."); + } catch (IllegalArgumentException expected) { + } + } +} diff --git a/tests/iketests/src/java/android/net/ipsec/ike/IkeSessionTest.java b/tests/iketests/src/java/android/net/ipsec/ike/IkeSessionTest.java new file mode 100644 index 00000000..8bf1281d --- /dev/null +++ b/tests/iketests/src/java/android/net/ipsec/ike/IkeSessionTest.java @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.ipsec.ike; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; + +import android.content.Context; +import android.net.IpSecManager; +import android.os.Looper; +import android.os.test.TestLooper; +import android.util.Log; + +import com.android.internal.net.ipsec.ike.IkeSessionStateMachine; +import com.android.internal.net.ipsec.ike.IkeSessionStateMachineTest; +import com.android.internal.net.ipsec.ike.testutils.MockIpSecTestUtils; + +import libcore.net.InetAddressUtils; + +import org.junit.Before; +import org.junit.Test; + +import java.net.Inet4Address; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; + +public final class IkeSessionTest { + private static final int TIMEOUT_MS = 500; + + private static final Inet4Address LOCAL_ADDRESS = + (Inet4Address) (InetAddressUtils.parseNumericAddress("192.0.2.200")); + private static final Inet4Address REMOTE_ADDRESS = + (Inet4Address) (InetAddressUtils.parseNumericAddress("127.0.0.1")); + + private MockIpSecTestUtils mMockIpSecTestUtils; + private IpSecManager mIpSecManager; + private Context mContext; + + private IkeSessionOptions mIkeSessionOptions; + private ChildSessionOptions mMockChildSessionOptions; + private Executor mUserCbExecutor; + private IkeSessionCallback mMockIkeSessionCb; + private ChildSessionCallback mMockChildSessionCb; + + @Before + public void setUp() throws Exception { + if (Looper.myLooper() == null) Looper.prepare(); + + mMockIpSecTestUtils = MockIpSecTestUtils.setUpMockIpSec(); + mIpSecManager = mMockIpSecTestUtils.getIpSecManager(); + mContext = mMockIpSecTestUtils.getContext(); + + mIkeSessionOptions = buildIkeSessionOptions(); + mMockChildSessionOptions = mock(ChildSessionOptions.class); + mUserCbExecutor = (r) -> r.run(); // Inline executor for testing purposes. + mMockIkeSessionCb = mock(IkeSessionCallback.class); + mMockChildSessionCb = mock(ChildSessionCallback.class); + } + + private IkeSessionOptions buildIkeSessionOptions() throws Exception { + return new IkeSessionOptions.Builder() + .setServerAddress(REMOTE_ADDRESS) + .setUdpEncapsulationSocket(mIpSecManager.openUdpEncapsulationSocket()) + .addSaProposal(IkeSessionStateMachineTest.buildSaProposal()) + .setLocalIdentification(new IkeIpv4AddrIdentification((Inet4Address) LOCAL_ADDRESS)) + .setRemoteIdentification( + new IkeIpv4AddrIdentification((Inet4Address) REMOTE_ADDRESS)) + .setAuthPsk(new byte[0] /* psk, unused */) + .build(); + } + + @Test + public void testConstructIkeSession() throws Exception { + IkeSession ikeSession = + new IkeSession( + mContext, + mIkeSessionOptions, + mMockChildSessionOptions, + mUserCbExecutor, + mMockIkeSessionCb, + mMockChildSessionCb); + assertNotNull(ikeSession.mIkeSessionStateMachine.getHandler().getLooper()); + } + + /** + * Test that when users construct IkeSessions from different threads, these IkeSessions will + * still be running on the same IKE worker thread. + */ + @Test + public void testConstructFromDifferentThreads() throws Exception { + final int numSession = 2; + IkeSession[] sessions = new IkeSession[numSession]; + + final CountDownLatch cntLatch = new CountDownLatch(2); + + for (int i = 0; i < numSession; i++) { + int index = i; + new Thread() { + @Override + public void run() { + try { + sessions[index] = + new IkeSession( + mContext, + mIkeSessionOptions, + mMockChildSessionOptions, + mUserCbExecutor, + mMockIkeSessionCb, + mMockChildSessionCb); + cntLatch.countDown(); + } catch (Exception e) { + Log.e("IkeSessionTest", "error encountered constructing IkeSession. ", e); + } + } + }.start(); + } + + assertTrue(cntLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + + // Verify that two sessions use the same looper. + assertEquals( + sessions[0].mIkeSessionStateMachine.getHandler().getLooper(), + sessions[1].mIkeSessionStateMachine.getHandler().getLooper()); + } + + @Test + public void testOpensIkeSession() throws Exception { + TestLooper testLooper = new TestLooper(); + IkeSession ikeSession = + new IkeSession( + testLooper.getLooper(), + mContext, + mIpSecManager, + mIkeSessionOptions, + mMockChildSessionOptions, + mUserCbExecutor, + mMockIkeSessionCb, + mMockChildSessionCb); + testLooper.dispatchAll(); + + assertTrue( + ikeSession.mIkeSessionStateMachine.getCurrentState() + instanceof IkeSessionStateMachine.CreateIkeLocalIkeInit); + } +} diff --git a/tests/iketests/src/java/android/net/ipsec/ike/IkeTrafficSelectorTest.java b/tests/iketests/src/java/android/net/ipsec/ike/IkeTrafficSelectorTest.java new file mode 100644 index 00000000..65cf0566 --- /dev/null +++ b/tests/iketests/src/java/android/net/ipsec/ike/IkeTrafficSelectorTest.java @@ -0,0 +1,312 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.ipsec.ike; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import com.android.internal.net.TestUtils; +import com.android.internal.net.ipsec.ike.exceptions.InvalidSyntaxException; + +import libcore.net.InetAddressUtils; + +import org.junit.Test; + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.nio.ByteBuffer; + +public final class IkeTrafficSelectorTest { + private static final String TS_IPV4_ONE_HEX_STRING = "070000100010fff0c0000264c0000365"; + private static final int TS_ONE_START_PORT = 16; + private static final int TS_ONE_END_PORT = 65520; + private static final Inet4Address TS_ONE_START_ADDRESS = + (Inet4Address) (InetAddressUtils.parseNumericAddress("192.0.2.100")); + private static final Inet4Address TS_ONE_END_ADDRESS = + (Inet4Address) (InetAddressUtils.parseNumericAddress("192.0.3.101")); + + private static final String TS_IPV4_TWO_HEX_STRING = "070000100000ffffc0000464c0000466"; + private static final int TS_TWO_START_PORT = 0; + private static final int TS_TWO_END_PORT = 65535; + private static final Inet4Address TS_TWO_START_ADDRESS = + (Inet4Address) (InetAddressUtils.parseNumericAddress("192.0.4.100")); + private static final Inet4Address TS_TWO_END_ADDRESS = + (Inet4Address) (InetAddressUtils.parseNumericAddress("192.0.4.102")); + + private static final String TX_IPV4_INVALID_PORT_RANGE_HEX_STRING = + "0700001022221111c0000464c0000466"; + private static final String TX_IPV4_INVALID_ADDRESS_RANGE_HEX_STRING = + "070000100000ffffc0000466c0000366"; + + private static final int TS_TYPE_OFFSET = 0; + private static final int PROTOCOL_ID_OFFSET = 1; + private static final int TS_LENGTH_OFFSET = 2; + + private IkeTrafficSelector mTsOne; + private IkeTrafficSelector mTsTwo; + + public IkeTrafficSelectorTest() { + mTsOne = + new IkeTrafficSelector( + IkeTrafficSelector.TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE, + TS_ONE_START_PORT, + TS_ONE_END_PORT, + TS_ONE_START_ADDRESS, + TS_ONE_END_ADDRESS); + mTsTwo = + new IkeTrafficSelector( + IkeTrafficSelector.TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE, + TS_TWO_START_PORT, + TS_TWO_END_PORT, + TS_TWO_START_ADDRESS, + TS_TWO_END_ADDRESS); + } + + @Test + public void testDecodeIkeTrafficSelectors() throws Exception { + int numTs = 2; + + byte[] tsBytes = + TestUtils.hexStringToByteArray(TS_IPV4_ONE_HEX_STRING + TS_IPV4_TWO_HEX_STRING); + IkeTrafficSelector[] selectors = + IkeTrafficSelector.decodeIkeTrafficSelectors(numTs, tsBytes); + + assertEquals(numTs, selectors.length); + + // Verify first traffic selector + IkeTrafficSelector tsOne = selectors[0]; + + assertEquals(IkeTrafficSelector.TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE, tsOne.tsType); + assertEquals(IkeTrafficSelector.IP_PROTOCOL_ID_UNSPEC, tsOne.ipProtocolId); + assertEquals(IkeTrafficSelector.TRAFFIC_SELECTOR_IPV4_LEN, tsOne.selectorLength); + assertEquals(TS_ONE_START_PORT, tsOne.startPort); + assertEquals(TS_ONE_END_PORT, tsOne.endPort); + assertEquals(TS_ONE_START_ADDRESS, tsOne.startingAddress); + assertEquals(TS_ONE_END_ADDRESS, tsOne.endingAddress); + + // Verify second traffic selector + IkeTrafficSelector tsTwo = selectors[1]; + + assertEquals(IkeTrafficSelector.TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE, tsTwo.tsType); + assertEquals(IkeTrafficSelector.IP_PROTOCOL_ID_UNSPEC, tsTwo.ipProtocolId); + assertEquals(IkeTrafficSelector.TRAFFIC_SELECTOR_IPV4_LEN, tsTwo.selectorLength); + assertEquals(TS_TWO_START_PORT, tsTwo.startPort); + assertEquals(TS_TWO_END_PORT, tsTwo.endPort); + assertEquals(TS_TWO_START_ADDRESS, tsTwo.startingAddress); + assertEquals(TS_TWO_END_ADDRESS, tsTwo.endingAddress); + } + + @Test + public void testBuildAndEncodeIkeTrafficSelector() throws Exception { + IkeTrafficSelector ts = + new IkeTrafficSelector( + IkeTrafficSelector.TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE, + TS_ONE_START_PORT, + TS_ONE_END_PORT, + TS_ONE_START_ADDRESS, + TS_ONE_END_ADDRESS); + + ByteBuffer byteBuffer = ByteBuffer.allocate(ts.selectorLength); + ts.encodeToByteBuffer(byteBuffer); + + byte[] expectedBytes = TestUtils.hexStringToByteArray(TS_IPV4_ONE_HEX_STRING); + assertArrayEquals(expectedBytes, byteBuffer.array()); + } + + @Test + public void testEquals() throws Exception { + IkeTrafficSelector tsOneOther = + new IkeTrafficSelector( + IkeTrafficSelector.TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE, + TS_ONE_START_PORT, + TS_ONE_END_PORT, + TS_ONE_START_ADDRESS, + TS_ONE_END_ADDRESS); + + assertEquals(mTsOne, tsOneOther); + assertNotEquals(mTsOne, mTsTwo); + } + + @Test + public void testContains() throws Exception { + IkeTrafficSelector tsOneSubset = + new IkeTrafficSelector( + IkeTrafficSelector.TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE, + TS_ONE_START_PORT + 1, + TS_ONE_END_PORT, + TS_ONE_START_ADDRESS, + TS_ONE_END_ADDRESS); + assertTrue(mTsOne.contains(tsOneSubset)); + assertFalse(tsOneSubset.contains(mTsOne)); + + assertTrue(mTsOne.contains(mTsOne)); + assertFalse(mTsOne.contains(mTsTwo)); + } + + @Test + public void testDecodeIkeTrafficSelectorWithInvalidTsType() throws Exception { + int numTs = 1; + byte[] tsBytes = TestUtils.hexStringToByteArray(TS_IPV4_ONE_HEX_STRING); + tsBytes[TS_TYPE_OFFSET] = -1; + + try { + IkeTrafficSelector.decodeIkeTrafficSelectors(numTs, tsBytes); + fail("Expected to fail due to invalid Traffic Selector Type."); + } catch (InvalidSyntaxException expected) { + + } + } + + @Test + public void testDecodeIkeTrafficSelectorWithInvalidIpProtocol() throws Exception { + int numTs = 1; + byte[] tsBytes = TestUtils.hexStringToByteArray(TS_IPV4_ONE_HEX_STRING); + tsBytes[PROTOCOL_ID_OFFSET] = -1; + + try { + IkeTrafficSelector.decodeIkeTrafficSelectors(numTs, tsBytes); + fail("Expected to fail due to invalid IP Protocol ID."); + } catch (InvalidSyntaxException expected) { + + } + } + + @Test + public void testDecodeIkeTrafficSelectorWithExpectedTrailing() throws Exception { + int numTs = 1; + byte[] tsBytes = TestUtils.hexStringToByteArray(TS_IPV4_ONE_HEX_STRING + "FFFF"); + + try { + IkeTrafficSelector.decodeIkeTrafficSelectors(numTs, tsBytes); + fail("Expected to fail due to unexpected trailing characters."); + } catch (InvalidSyntaxException expected) { + + } + } + + @Test + public void testDecodeIkeTrafficSelectorWithInvalidTsLength() throws Exception { + int numTs = 1; + byte[] tsBytes = TestUtils.hexStringToByteArray(TS_IPV4_ONE_HEX_STRING); + + // Traffic Selector field is two octets + tsBytes[TS_LENGTH_OFFSET] = 0; + tsBytes[TS_LENGTH_OFFSET + 1] = 0; + + try { + IkeTrafficSelector.decodeIkeTrafficSelectors(numTs, tsBytes); + fail("Expected to fail due to invalid Traffic Selector length."); + } catch (InvalidSyntaxException expected) { + + } + } + + @Test + public void testDecodeIkeTrafficSelectorWithInvalidPortRange() throws Exception { + int numTs = 1; + byte[] tsBytes = TestUtils.hexStringToByteArray(TX_IPV4_INVALID_PORT_RANGE_HEX_STRING); + + try { + IkeTrafficSelector.decodeIkeTrafficSelectors(numTs, tsBytes); + fail("Expected to fail when start port is larger than end port."); + } catch (InvalidSyntaxException expected) { + + } + } + + @Test + public void testDecodeIkeTrafficSelectorWithInvalidAddressRange() throws Exception { + int numTs = 1; + byte[] tsBytes = TestUtils.hexStringToByteArray(TX_IPV4_INVALID_ADDRESS_RANGE_HEX_STRING); + + try { + IkeTrafficSelector.decodeIkeTrafficSelectors(numTs, tsBytes); + fail("Expected to fail when starting address is larger than ending address."); + } catch (InvalidSyntaxException expected) { + + } + } + + @Test + public void testBuildIkeTrafficSelectorWithInvalidTsType() throws Exception { + try { + IkeTrafficSelector ts = + new IkeTrafficSelector( + 0, + TS_ONE_START_PORT, + TS_ONE_END_PORT, + TS_ONE_START_ADDRESS, + TS_ONE_END_ADDRESS); + fail("Expected to fail due to unrecognized Traffic Selector type."); + } catch (IllegalArgumentException expected) { + + } + } + + @Test + public void testBuildIkeTrafficSelectorWithInvalidPortRange() throws Exception { + try { + IkeTrafficSelector ts = + new IkeTrafficSelector( + IkeTrafficSelector.TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE, + TS_ONE_END_PORT, + TS_ONE_START_PORT, + TS_ONE_START_ADDRESS, + TS_ONE_END_ADDRESS); + fail("Expected to fail due to invalid port range."); + } catch (IllegalArgumentException expected) { + + } + } + + @Test + public void testBuildIkeTrafficSelectorWithMismatchedAddressType() throws Exception { + Inet6Address inet6Address = + (Inet6Address) (InetAddressUtils.parseNumericAddress("0:2001:0:db8::1")); + try { + IkeTrafficSelector ts = + new IkeTrafficSelector( + IkeTrafficSelector.TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE, + TS_ONE_START_PORT, + TS_ONE_END_PORT, + inet6Address, + TS_ONE_END_ADDRESS); + fail("Expected to fail due to mismatched address format."); + } catch (IllegalArgumentException expected) { + + } + } + + @Test + public void testBuildIkeTrafficSelectorWithInvalidAddressRange() throws Exception { + try { + IkeTrafficSelector ts = + new IkeTrafficSelector( + IkeTrafficSelector.TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE, + TS_ONE_START_PORT, + TS_ONE_END_PORT, + TS_ONE_END_ADDRESS, + TS_ONE_START_ADDRESS); + fail("Expected to fail due to invalid address range."); + } catch (IllegalArgumentException e) { + } + } +} diff --git a/tests/iketests/src/java/android/net/ipsec/ike/SaProposalTest.java b/tests/iketests/src/java/android/net/ipsec/ike/SaProposalTest.java new file mode 100644 index 00000000..d4efb0c3 --- /dev/null +++ b/tests/iketests/src/java/android/net/ipsec/ike/SaProposalTest.java @@ -0,0 +1,321 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.ipsec.ike; + +import static android.net.ipsec.ike.SaProposal.KEY_LEN_AES_128; +import static android.net.ipsec.ike.SaProposal.KEY_LEN_UNUSED; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import com.android.internal.net.ipsec.ike.message.IkePayload; +import com.android.internal.net.ipsec.ike.message.IkeSaPayload.DhGroupTransform; +import com.android.internal.net.ipsec.ike.message.IkeSaPayload.EncryptionTransform; +import com.android.internal.net.ipsec.ike.message.IkeSaPayload.IntegrityTransform; +import com.android.internal.net.ipsec.ike.message.IkeSaPayload.PrfTransform; +import com.android.internal.net.ipsec.ike.message.IkeSaPayload.Transform; + +import org.junit.Test; + +public final class SaProposalTest { + private final EncryptionTransform mEncryption3DesTransform; + private final EncryptionTransform mEncryptionAesGcm8Transform; + private final EncryptionTransform mEncryptionAesGcm12Transform; + private final IntegrityTransform mIntegrityHmacSha1Transform; + private final IntegrityTransform mIntegrityNoneTransform; + private final PrfTransform mPrfAes128XCbcTransform; + private final DhGroupTransform mDhGroup1024Transform; + + public SaProposalTest() { + mEncryption3DesTransform = + new EncryptionTransform(SaProposal.ENCRYPTION_ALGORITHM_3DES, KEY_LEN_UNUSED); + mEncryptionAesGcm8Transform = + new EncryptionTransform( + SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8, SaProposal.KEY_LEN_AES_128); + mEncryptionAesGcm12Transform = + new EncryptionTransform( + SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12, SaProposal.KEY_LEN_AES_128); + mIntegrityHmacSha1Transform = + new IntegrityTransform(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96); + mIntegrityNoneTransform = new IntegrityTransform(SaProposal.INTEGRITY_ALGORITHM_NONE); + mPrfAes128XCbcTransform = new PrfTransform(SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC); + mDhGroup1024Transform = new DhGroupTransform(SaProposal.DH_GROUP_1024_BIT_MODP); + } + + @Test + public void testBuildIkeSaProposalWithNormalModeCipher() throws Exception { + IkeSaProposal proposal = + new IkeSaProposal.Builder() + .addEncryptionAlgorithm( + SaProposal.ENCRYPTION_ALGORITHM_3DES, KEY_LEN_UNUSED) + .addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96) + .addPseudorandomFunction(SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC) + .addDhGroup(SaProposal.DH_GROUP_1024_BIT_MODP) + .build(); + + assertEquals(IkePayload.PROTOCOL_ID_IKE, proposal.getProtocolId()); + assertArrayEquals( + new EncryptionTransform[] {mEncryption3DesTransform}, + proposal.getEncryptionTransforms()); + assertArrayEquals( + new IntegrityTransform[] {mIntegrityHmacSha1Transform}, + proposal.getIntegrityTransforms()); + assertArrayEquals( + new PrfTransform[] {mPrfAes128XCbcTransform}, proposal.getPrfTransforms()); + assertArrayEquals( + new DhGroupTransform[] {mDhGroup1024Transform}, proposal.getDhGroupTransforms()); + } + + @Test + public void testBuildIkeSaProposalWithCombinedModeCipher() throws Exception { + IkeSaProposal proposal = + new IkeSaProposal.Builder() + .addEncryptionAlgorithm( + SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8, + SaProposal.KEY_LEN_AES_128) + .addPseudorandomFunction(SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC) + .addDhGroup(SaProposal.DH_GROUP_1024_BIT_MODP) + .build(); + + assertEquals(IkePayload.PROTOCOL_ID_IKE, proposal.getProtocolId()); + assertArrayEquals( + new EncryptionTransform[] {mEncryptionAesGcm8Transform}, + proposal.getEncryptionTransforms()); + assertArrayEquals( + new PrfTransform[] {mPrfAes128XCbcTransform}, proposal.getPrfTransforms()); + assertArrayEquals( + new DhGroupTransform[] {mDhGroup1024Transform}, proposal.getDhGroupTransforms()); + assertTrue(proposal.getIntegrityTransforms().length == 0); + } + + @Test + public void testBuildChildSaProposalWithNormalCipher() throws Exception { + ChildSaProposal proposal = + new ChildSaProposal.Builder() + .addEncryptionAlgorithm( + SaProposal.ENCRYPTION_ALGORITHM_3DES, KEY_LEN_UNUSED) + .addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_NONE) + .addDhGroup(SaProposal.DH_GROUP_1024_BIT_MODP) + .build(); + + assertEquals(IkePayload.PROTOCOL_ID_ESP, proposal.getProtocolId()); + assertArrayEquals( + new EncryptionTransform[] {mEncryption3DesTransform}, + proposal.getEncryptionTransforms()); + assertArrayEquals( + new IntegrityTransform[] {mIntegrityNoneTransform}, + proposal.getIntegrityTransforms()); + assertArrayEquals( + new DhGroupTransform[] {mDhGroup1024Transform}, proposal.getDhGroupTransforms()); + } + + @Test + public void testGetCopyWithoutDhGroup() throws Exception { + ChildSaProposal proposal = + new ChildSaProposal.Builder() + .addEncryptionAlgorithm( + SaProposal.ENCRYPTION_ALGORITHM_3DES, KEY_LEN_UNUSED) + .addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_NONE) + .addDhGroup(SaProposal.DH_GROUP_1024_BIT_MODP) + .build(); + ChildSaProposal proposalWithoutDh = proposal.getCopyWithoutDhTransform(); + + assertArrayEquals( + proposal.getEncryptionTransforms(), proposalWithoutDh.getEncryptionTransforms()); + assertArrayEquals( + proposal.getIntegrityTransforms(), proposalWithoutDh.getIntegrityTransforms()); + assertTrue(proposal.getDhGroupTransforms().length == 1); + assertTrue(proposalWithoutDh.getDhGroupTransforms().length == 0); + } + + @Test + public void testBuildEncryptAlgosWithNoAlgorithm() throws Exception { + try { + new IkeSaProposal.Builder().build(); + fail("Expected to fail when no encryption algorithm is proposed."); + } catch (IllegalArgumentException expected) { + + } + } + + @Test + public void testBuildEncryptAlgosWithUnrecognizedAlgorithm() throws Exception { + try { + new IkeSaProposal.Builder().addEncryptionAlgorithm(-1, KEY_LEN_UNUSED); + fail("Expected to fail when unrecognized encryption algorithm is proposed."); + } catch (IllegalArgumentException expected) { + + } + } + + @Test + public void testBuildEncryptAlgosWithTwoModes() throws Exception { + try { + new IkeSaProposal.Builder() + .addEncryptionAlgorithm(SaProposal.ENCRYPTION_ALGORITHM_3DES, KEY_LEN_UNUSED) + .addEncryptionAlgorithm( + SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12, KEY_LEN_AES_128); + fail( + "Expected to fail when " + + "normal and combined-mode ciphers are proposed together."); + } catch (IllegalArgumentException expected) { + + } + } + + @Test + public void testBuildIkeProposalWithoutPrf() throws Exception { + try { + new IkeSaProposal.Builder() + .addEncryptionAlgorithm(SaProposal.ENCRYPTION_ALGORITHM_3DES, KEY_LEN_UNUSED) + .build(); + fail("Expected to fail when PRF is not provided in IKE SA proposal."); + } catch (IllegalArgumentException expected) { + + } + } + + // Test throwing exception when building IKE SA Proposal with AEAD and not-none integrity + // algorithm. + @Test + public void testBuildAeadWithIntegrityAlgo() throws Exception { + try { + new ChildSaProposal.Builder() + .addEncryptionAlgorithm( + SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12, KEY_LEN_AES_128) + .addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_NONE) + .addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96) + .build(); + + fail("Expected to fail when not-none integrity algorithm is proposed with AEAD"); + } catch (IllegalArgumentException expected) { + + } + } + + // Test throwing exception when building IKE SA Proposal with normal mode cipher and without + // integrity algorithm. + @Test + public void testBuildIkeProposalNormalCipherWithoutIntegrityAlgo() throws Exception { + try { + new IkeSaProposal.Builder() + .addEncryptionAlgorithm(SaProposal.ENCRYPTION_ALGORITHM_3DES, KEY_LEN_UNUSED) + .addPseudorandomFunction(SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1) + .build(); + + fail( + "Expected to fail when" + + " no integrity algorithm is proposed with non-combined cipher"); + } catch (IllegalArgumentException expected) { + + } + } + + // Test throwing exception when building IKE SA Proposal with normal mode cipher and none-value + // integrity algorithm. + @Test + public void testBuildIkeProposalNormalCipherWithNoneValueIntegrityAlgo() throws Exception { + try { + new IkeSaProposal.Builder() + .addEncryptionAlgorithm(SaProposal.ENCRYPTION_ALGORITHM_3DES, KEY_LEN_UNUSED) + .addPseudorandomFunction(SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1) + .addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_NONE) + .addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96) + .build(); + + fail( + "Expected to fail when none-value integrity algorithm is proposed" + + " with non-combined cipher"); + } catch (IllegalArgumentException expected) { + + } + } + + @Test + public void testBuildIkeProposalWithoutDhGroup() throws Exception { + try { + new IkeSaProposal.Builder() + .addEncryptionAlgorithm(SaProposal.ENCRYPTION_ALGORITHM_3DES, KEY_LEN_UNUSED) + .addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96) + .addPseudorandomFunction(SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC) + .build(); + + fail("Expected to fail when no DH Group is proposed in IKE SA proposal."); + } catch (IllegalArgumentException expected) { + + } + } + + @Test + public void testBuildIkeProposalWithNoneValueDhGroup() throws Exception { + try { + new IkeSaProposal.Builder() + .addEncryptionAlgorithm(SaProposal.ENCRYPTION_ALGORITHM_3DES, KEY_LEN_UNUSED) + .addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96) + .addPseudorandomFunction(SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC) + .addDhGroup(SaProposal.DH_GROUP_1024_BIT_MODP) + .addDhGroup(SaProposal.DH_GROUP_NONE) + .build(); + + fail("Expected to fail when none-value DH Group is proposed in IKE SA proposal."); + } catch (IllegalArgumentException expected) { + + } + } + + @Test + public void testIsTransformSelectedFrom() throws Exception { + assertTrue(SaProposal.isTransformSelectedFrom(new Transform[0], new Transform[0])); + assertTrue( + SaProposal.isTransformSelectedFrom( + new Transform[] {mEncryptionAesGcm8Transform}, + new Transform[] { + mEncryptionAesGcm8Transform, mEncryptionAesGcm12Transform + })); + assertTrue( + SaProposal.isTransformSelectedFrom( + new Transform[] {mIntegrityNoneTransform}, + new Transform[] {mIntegrityNoneTransform})); + + // No transform selected. + assertFalse( + SaProposal.isTransformSelectedFrom( + new Transform[0], new Transform[] {mEncryptionAesGcm8Transform})); + + // Selected transform was not part of original proposal. + assertFalse( + SaProposal.isTransformSelectedFrom( + new Transform[] {mPrfAes128XCbcTransform}, new Transform[0])); + + // More than one transform returned. + assertFalse( + SaProposal.isTransformSelectedFrom( + new Transform[] {mEncryptionAesGcm8Transform, mEncryptionAesGcm12Transform}, + new Transform[] { + mEncryptionAesGcm8Transform, mEncryptionAesGcm12Transform + })); + + // Selected transform was not part of original proposal. + assertFalse( + SaProposal.isTransformSelectedFrom( + new Transform[] {mIntegrityNoneTransform}, + new Transform[] {mIntegrityHmacSha1Transform})); + } +} diff --git a/tests/iketests/src/java/android/net/ipsec/ike/TunnelModeChildSessionOptionsTest.java b/tests/iketests/src/java/android/net/ipsec/ike/TunnelModeChildSessionOptionsTest.java new file mode 100644 index 00000000..b0f81dc2 --- /dev/null +++ b/tests/iketests/src/java/android/net/ipsec/ike/TunnelModeChildSessionOptionsTest.java @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.ipsec.ike; + +import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.AF_INET6; + +import static com.android.internal.net.ipsec.ike.message.IkeConfigPayload.CONFIG_ATTR_INTERNAL_IP4_ADDRESS; +import static com.android.internal.net.ipsec.ike.message.IkeConfigPayload.CONFIG_ATTR_INTERNAL_IP4_DHCP; +import static com.android.internal.net.ipsec.ike.message.IkeConfigPayload.CONFIG_ATTR_INTERNAL_IP4_DNS; +import static com.android.internal.net.ipsec.ike.message.IkeConfigPayload.CONFIG_ATTR_INTERNAL_IP4_NETMASK; +import static com.android.internal.net.ipsec.ike.message.IkeConfigPayload.CONFIG_ATTR_INTERNAL_IP4_SUBNET; +import static com.android.internal.net.ipsec.ike.message.IkeConfigPayload.CONFIG_ATTR_INTERNAL_IP6_ADDRESS; +import static com.android.internal.net.ipsec.ike.message.IkeConfigPayload.CONFIG_ATTR_INTERNAL_IP6_DNS; +import static com.android.internal.net.ipsec.ike.message.IkeConfigPayload.CONFIG_ATTR_INTERNAL_IP6_SUBNET; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + +import android.util.SparseArray; + +import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttribute; + +import libcore.net.InetAddressUtils; + +import org.junit.Before; +import org.junit.Test; + +import java.net.Inet4Address; +import java.net.Inet6Address; + +public final class TunnelModeChildSessionOptionsTest { + private static final int NUM_TS = 1; + + private static final int IP4_PREFIX_LEN = 32; + private static final int IP6_PREFIX_LEN = 64; + + private static final int INVALID_ADDR_FAMILY = 5; + + private static final Inet4Address IPV4_ADDRESS = + (Inet4Address) (InetAddressUtils.parseNumericAddress("192.0.2.100")); + private static final Inet6Address IPV6_ADDRESS = + (Inet6Address) (InetAddressUtils.parseNumericAddress("2001:db8::1")); + + private static final Inet4Address IPV4_DNS_SERVER = + (Inet4Address) (InetAddressUtils.parseNumericAddress("8.8.8.8")); + private static final Inet6Address IPV6_DNS_SERVER = + (Inet6Address) (InetAddressUtils.parseNumericAddress("2001:4860:4860::8888")); + + private static final Inet4Address IPV4_DHCP_SERVER = + (Inet4Address) (InetAddressUtils.parseNumericAddress("192.0.2.200")); + private ChildSaProposal mSaProposal; + + @Before + public void setup() { + mSaProposal = + new ChildSaProposal.Builder() + .addEncryptionAlgorithm( + SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12, + SaProposal.KEY_LEN_AES_128) + .build(); + } + + private void verifyCommon(TunnelModeChildSessionOptions childOptions) { + assertArrayEquals(new SaProposal[] {mSaProposal}, childOptions.getSaProposals()); + assertEquals(NUM_TS, childOptions.getLocalTrafficSelectors().length); + assertEquals(NUM_TS, childOptions.getRemoteTrafficSelectors().length); + assertFalse(childOptions.isTransportMode()); + } + + private void verifyAttrTypes( + SparseArray expectedAttrCntMap, TunnelModeChildSessionOptions childOptions) { + ConfigAttribute[] configAttributes = childOptions.getConfigurationRequests(); + + SparseArray<Integer> atrrCntMap = expectedAttrCntMap.clone(); + + for (int i = 0; i < configAttributes.length; i++) { + int attType = configAttributes[i].attributeType; + assertNotNull(atrrCntMap.get(attType)); + + atrrCntMap.put(attType, atrrCntMap.get(attType) - 1); + if (atrrCntMap.get(attType) == 0) atrrCntMap.remove(attType); + } + + assertEquals(0, atrrCntMap.size()); + } + + @Test + public void testBuildChildSessionOptionsWithoutConfigReq() { + TunnelModeChildSessionOptions childOptions = + new TunnelModeChildSessionOptions.Builder().addSaProposal(mSaProposal).build(); + + verifyCommon(childOptions); + assertEquals(0, childOptions.getConfigurationRequests().length); + } + + @Test + public void testBuildChildSessionOptionsWithAddressReq() { + TunnelModeChildSessionOptions childOptions = + new TunnelModeChildSessionOptions.Builder() + .addSaProposal(mSaProposal) + .addInternalAddressRequest(AF_INET, 1) + .addInternalAddressRequest(AF_INET6, 2) + .addInternalAddressRequest(IPV4_ADDRESS, IP4_PREFIX_LEN) + .addInternalAddressRequest(IPV6_ADDRESS, IP6_PREFIX_LEN) + .build(); + + verifyCommon(childOptions); + + SparseArray<Integer> expectedAttrCntMap = new SparseArray<>(); + expectedAttrCntMap.put(CONFIG_ATTR_INTERNAL_IP4_ADDRESS, 2); + expectedAttrCntMap.put(CONFIG_ATTR_INTERNAL_IP6_ADDRESS, 3); + expectedAttrCntMap.put(CONFIG_ATTR_INTERNAL_IP4_NETMASK, 1); + + verifyAttrTypes(expectedAttrCntMap, childOptions); + } + + @Test + public void testBuildChildSessionOptionsWithInvalidAddressReq() { + try { + new TunnelModeChildSessionOptions.Builder() + .addSaProposal(mSaProposal) + .addInternalAddressRequest(IPV4_ADDRESS, 31) + .build(); + fail("Expected to fail due to invalid IPv4 prefix length."); + } catch (IllegalArgumentException expected) { + + } + } + + @Test + public void testBuildChildSessionOptionsWithDnsServerReq() { + TunnelModeChildSessionOptions childOptions = + new TunnelModeChildSessionOptions.Builder() + .addSaProposal(mSaProposal) + .addInternalDnsServerRequest(AF_INET, 1) + .addInternalDnsServerRequest(AF_INET6, 1) + .addInternalDnsServerRequest(IPV4_DNS_SERVER) + .addInternalDnsServerRequest(IPV6_DNS_SERVER) + .build(); + + verifyCommon(childOptions); + + SparseArray<Integer> expectedAttrCntMap = new SparseArray<>(); + expectedAttrCntMap.put(CONFIG_ATTR_INTERNAL_IP4_DNS, 2); + expectedAttrCntMap.put(CONFIG_ATTR_INTERNAL_IP6_DNS, 2); + + verifyAttrTypes(expectedAttrCntMap, childOptions); + } + + @Test + public void testBuildChildSessionOptionsWithSubnetReq() { + TunnelModeChildSessionOptions childOptions = + new TunnelModeChildSessionOptions.Builder() + .addSaProposal(mSaProposal) + .addInternalSubnetRequest(AF_INET, 1) + .addInternalSubnetRequest(AF_INET6, 1) + .build(); + + verifyCommon(childOptions); + + SparseArray<Integer> expectedAttrCntMap = new SparseArray<>(); + expectedAttrCntMap.put(CONFIG_ATTR_INTERNAL_IP4_SUBNET, 1); + expectedAttrCntMap.put(CONFIG_ATTR_INTERNAL_IP6_SUBNET, 1); + + verifyAttrTypes(expectedAttrCntMap, childOptions); + } + + @Test + public void testBuildChildSessionOptionsWithDhcpServerReq() { + TunnelModeChildSessionOptions childOptions = + new TunnelModeChildSessionOptions.Builder() + .addSaProposal(mSaProposal) + .addInternalDhcpServerRequest(AF_INET, 3) + .addInternalDhcpServerRequest(IPV4_DHCP_SERVER) + .build(); + + verifyCommon(childOptions); + + SparseArray<Integer> expectedAttrCntMap = new SparseArray<>(); + expectedAttrCntMap.put(CONFIG_ATTR_INTERNAL_IP4_DHCP, 4); + + verifyAttrTypes(expectedAttrCntMap, childOptions); + } + + @Test + public void testBuildChildSessionOptionsWithDhcp6SeverReq() { + try { + new TunnelModeChildSessionOptions.Builder() + .addSaProposal(mSaProposal) + .addInternalDhcpServerRequest(AF_INET6, 3) + .build(); + fail("Expected to fail because DHCP6 is not supported."); + } catch (IllegalArgumentException expected) { + + } + } + + @Test + public void testBuildChildSessionOptionsWithInvalidDhcpReq() { + try { + new TunnelModeChildSessionOptions.Builder() + .addSaProposal(mSaProposal) + .addInternalDhcpServerRequest(INVALID_ADDR_FAMILY, 3) + .build(); + fail("Expected to fail due to invalid address family value"); + } catch (IllegalArgumentException expected) { + + } + } +} + diff --git a/tests/iketests/src/java/android/net/ipsec/ike/exceptions/IkeProtocolExceptionTest.java b/tests/iketests/src/java/android/net/ipsec/ike/exceptions/IkeProtocolExceptionTest.java new file mode 100644 index 00000000..8c3b16da --- /dev/null +++ b/tests/iketests/src/java/android/net/ipsec/ike/exceptions/IkeProtocolExceptionTest.java @@ -0,0 +1,58 @@ +/* + * 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.ipsec.ike.exceptions; + +import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_NO_PROPOSAL_CHOSEN; +import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_UNSUPPORTED_CRITICAL_PAYLOAD; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +import com.android.internal.net.ipsec.ike.exceptions.NoValidProposalChosenException; +import com.android.internal.net.ipsec.ike.exceptions.UnsupportedCriticalPayloadException; +import com.android.internal.net.ipsec.ike.message.IkeNotifyPayload; + +import org.junit.Test; + +import java.util.LinkedList; +import java.util.List; + +public final class IkeProtocolExceptionTest { + @Test + public void buildNotifyPayloadWithData() throws Exception { + List<Integer> unsupportedTypes = new LinkedList<>(); + unsupportedTypes.add(55); // 0x37 in hex + unsupportedTypes.add(56); + unsupportedTypes.add(57); + UnsupportedCriticalPayloadException exception = + new UnsupportedCriticalPayloadException(unsupportedTypes); + + IkeNotifyPayload payload = exception.buildNotifyPayload(); + assertEquals(ERROR_TYPE_UNSUPPORTED_CRITICAL_PAYLOAD, payload.notifyType); + assertArrayEquals(new byte[] {(byte) 0x37}, payload.notifyData); + } + + @Test + public void buildNotifyPayloadWithoutData() throws Exception { + NoValidProposalChosenException exception = + new NoValidProposalChosenException("IkeProtocolExceptionTest"); + + IkeNotifyPayload payload = exception.buildNotifyPayload(); + assertEquals(ERROR_TYPE_NO_PROPOSAL_CHOSEN, payload.notifyType); + assertArrayEquals(new byte[0], payload.notifyData); + } +} |