/*
 * 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.IkeSessionParams.IKE_DPD_DELAY_SEC_DEFAULT;
import static android.net.ipsec.ike.IkeSessionParams.IKE_HARD_LIFETIME_SEC_DEFAULT;
import static android.net.ipsec.ike.IkeSessionParams.IKE_HARD_LIFETIME_SEC_MAXIMUM;
import static android.net.ipsec.ike.IkeSessionParams.IKE_HARD_LIFETIME_SEC_MINIMUM;
import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_ACCEPT_ANY_REMOTE_ID;
import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_EAP_ONLY_AUTH;
import static android.net.ipsec.ike.IkeSessionParams.IKE_RETRANS_TIMEOUT_MS_LIST_DEFAULT;
import static android.net.ipsec.ike.IkeSessionParams.IKE_SOFT_LIFETIME_SEC_DEFAULT;
import static android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig;
import static android.net.ipsec.ike.IkeSessionParams.IkeAuthDigitalSignLocalConfig;
import static android.net.ipsec.ike.IkeSessionParams.IkeAuthDigitalSignRemoteConfig;
import static android.net.ipsec.ike.IkeSessionParams.IkeAuthEapConfig;
import static android.net.ipsec.ike.IkeSessionParams.IkeAuthPskConfig;
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_IP4_PCSCF;
import static com.android.internal.net.ipsec.ike.message.IkeConfigPayload.CONFIG_ATTR_IP6_PCSCF;
import static com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttribute;

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.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.InetAddresses;
import android.net.Network;
import android.net.SocketKeepalive;
import android.net.eap.EapSessionConfig;
import android.net.ipsec.ike.ike3gpp.Ike3gppExtension;
import android.net.ipsec.ike.ike3gpp.Ike3gppExtension.Ike3gppDataListener;
import android.net.ipsec.ike.ike3gpp.Ike3gppParams;
import android.os.PersistableBundle;
import android.telephony.TelephonyManager;
import android.util.SparseArray;

import com.android.internal.net.TestUtils;
import com.android.internal.net.ipsec.ike.testutils.CertUtils;

import org.junit.Before;
import org.junit.Test;

import java.net.Inet4Address;
import java.net.Inet6Address;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.security.interfaces.DSAPrivateKey;
import java.security.interfaces.RSAKey;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;

public final class IkeSessionParamsTest {
    private static final int IKE_OPTION_INVALID = -1;
    private static final int SUB_ID = 0;

    private static final String PSK_HEX_STRING = "6A756E69706572313233";
    private static final byte[] PSK = TestUtils.hexStringToByteArray(PSK_HEX_STRING);

    private static final String LOCAL_IPV4_HOST_ADDRESS = "192.0.2.100";
    private static final String REMOTE_IPV4_HOST_ADDRESS = "192.0.2.100";
    private static final String REMOTE_HOSTNAME = "server.test.android.net";

    private static final Inet4Address LOCAL_IPV4_ADDRESS =
            (Inet4Address) InetAddresses.parseNumericAddress(LOCAL_IPV4_HOST_ADDRESS);
    private static final Inet4Address REMOTE_IPV4_ADDRESS =
            (Inet4Address) InetAddresses.parseNumericAddress(REMOTE_IPV4_HOST_ADDRESS);

    private static final Inet4Address PCSCF_IPV4_ADDRESS_1 =
            (Inet4Address) InetAddresses.parseNumericAddress("192.0.2.1");
    private static final Inet4Address PCSCF_IPV4_ADDRESS_2 =
            (Inet4Address) InetAddresses.parseNumericAddress("192.0.2.2");
    private static final Inet6Address PCSCF_IPV6_ADDRESS_1 =
            (Inet6Address) InetAddresses.parseNumericAddress("2001:DB8::1");
    private static final Inet6Address PCSCF_IPV6_ADDRESS_2 =
            (Inet6Address) InetAddresses.parseNumericAddress("2001:DB8::2");

    private static final String EAP_MSCHAP_V2_USERNAME = "username";
    private static final String EAP_MSCHAP_V2_PASSWORD = "password";

    private Context mMockContext;
    private ConnectivityManager mMockConnectManager;
    private Network mMockDefaultNetwork;
    private Network mMockUserConfigNetwork;

    private IkeSaProposal mIkeSaProposal;
    private IkeIdentification mLocalIdentification;
    private IkeIdentification mRemoteIdentification;

    private interface TestRSAPrivateKey extends PrivateKey, RSAKey {}

    private X509Certificate mMockServerCaCert;
    private X509Certificate mMockClientEndCert;
    private TestRSAPrivateKey mMockRsaPrivateKey;

    @Before
    public void setUp() throws Exception {
        mMockContext = mock(Context.class);
        mMockConnectManager = mock(ConnectivityManager.class);
        mMockDefaultNetwork = mock(Network.class);
        mMockUserConfigNetwork = mock(Network.class);

        doReturn(Context.CONNECTIVITY_SERVICE)
                .when(mMockContext)
                .getSystemServiceName(ConnectivityManager.class);
        doReturn(mMockConnectManager)
                .when(mMockContext)
                .getSystemService(Context.CONNECTIVITY_SERVICE);
        when(mMockConnectManager.getActiveNetwork()).thenReturn(mMockDefaultNetwork);

        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(TestRSAPrivateKey.class);
    }

    private void verifyIkeParamsWithSeverIpAndDefaultValues(IkeSessionParams sessionParams) {
        verifyIkeSessionParamsCommon(sessionParams);

        assertEquals(REMOTE_IPV4_HOST_ADDRESS, sessionParams.getServerHostname());
        assertFalse(sessionParams.hasIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID));
        assertEquals(IKE_DPD_DELAY_SEC_DEFAULT, sessionParams.getDpdDelaySeconds());
        assertArrayEquals(
                IKE_RETRANS_TIMEOUT_MS_LIST_DEFAULT,
                sessionParams.getRetransmissionTimeoutsMillis());
    }

    private void verifyIkeSessionParamsCommon(IkeSessionParams sessionParams) {
        assertArrayEquals(
                new SaProposal[] {mIkeSaProposal}, sessionParams.getSaProposalsInternal());

        assertEquals(mLocalIdentification, sessionParams.getLocalIdentification());
        assertEquals(mRemoteIdentification, sessionParams.getRemoteIdentification());

        assertTrue(sessionParams.isIkeFragmentationSupported());
    }

    private void verifyAuthPskConfig(IkeSessionParams sessionParams) {
        IkeAuthConfig localConfig = sessionParams.getLocalAuthConfig();
        assertTrue(localConfig instanceof IkeAuthPskConfig);
        assertEquals(IkeSessionParams.IKE_AUTH_METHOD_PSK, localConfig.mAuthMethod);
        assertArrayEquals(PSK, ((IkeAuthPskConfig) localConfig).mPsk);

        IkeAuthConfig remoteConfig = sessionParams.getRemoteAuthConfig();
        assertTrue(remoteConfig instanceof IkeAuthPskConfig);
        assertEquals(IkeSessionParams.IKE_AUTH_METHOD_PSK, remoteConfig.mAuthMethod);
        assertArrayEquals(PSK, ((IkeAuthPskConfig) remoteConfig).mPsk);
    }

    private IkeSessionParams.Builder buildWithPskCommon(String hostname) {
        return new IkeSessionParams.Builder(mMockConnectManager)
                .setServerHostname(hostname)
                .addSaProposal(mIkeSaProposal)
                .setLocalIdentification(mLocalIdentification)
                .setRemoteIdentification(mRemoteIdentification)
                .setAuthPsk(PSK);
    }

    @Test
    public void testBuildWithPsk() throws Exception {
        IkeSessionParams sessionParams = buildWithPskCommon(REMOTE_IPV4_HOST_ADDRESS).build();

        verifyIkeParamsWithSeverIpAndDefaultValues(sessionParams);
        verifyAuthPskConfig(sessionParams);

        assertEquals(mMockDefaultNetwork, sessionParams.getNetwork());
        assertNull(sessionParams.getConfiguredNetwork());

        assertEquals(IKE_HARD_LIFETIME_SEC_DEFAULT, sessionParams.getHardLifetimeSeconds());
        assertEquals(IKE_SOFT_LIFETIME_SEC_DEFAULT, sessionParams.getSoftLifetimeSeconds());
    }

    @Test
    public void testBuildWithPskAndLifetime() throws Exception {
        int hardLifetimeSec = (int) TimeUnit.HOURS.toSeconds(20L);
        int softLifetimeSec = (int) TimeUnit.HOURS.toSeconds(10L);

        IkeSessionParams sessionParams =
                buildWithPskCommon(REMOTE_IPV4_HOST_ADDRESS)
                        .setLifetimeSeconds(hardLifetimeSec, softLifetimeSec)
                        .build();

        verifyIkeParamsWithSeverIpAndDefaultValues(sessionParams);
        verifyAuthPskConfig(sessionParams);

        assertEquals(hardLifetimeSec, sessionParams.getHardLifetimeSeconds());
        assertEquals(softLifetimeSec, sessionParams.getSoftLifetimeSeconds());
    }

    @Test
    public void testBuildWithPskAndHostname() throws Exception {
        IkeSessionParams sessionParams = buildWithPskCommon(REMOTE_HOSTNAME).build();

        verifyIkeSessionParamsCommon(sessionParams);
        verifyAuthPskConfig(sessionParams);

        assertEquals(REMOTE_HOSTNAME, sessionParams.getServerHostname());
    }

    @Test
    public void testAddIkeOption() throws Exception {
        IkeSessionParams sessionParams =
                buildWithPskCommon(REMOTE_IPV4_HOST_ADDRESS)
                        .addIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID)
                        .build();

        verifyIkeSessionParamsCommon(sessionParams);
        verifyAuthPskConfig(sessionParams);

        assertTrue(sessionParams.hasIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID));
    }

    @Test
    public void testAddAndRemoveIkeOption() throws Exception {
        IkeSessionParams sessionParams =
                buildWithPskCommon(REMOTE_IPV4_HOST_ADDRESS)
                        .addIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID)
                        .removeIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID)
                        .build();

        verifyIkeSessionParamsCommon(sessionParams);
        verifyAuthPskConfig(sessionParams);

        assertFalse(sessionParams.hasIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID));
    }

    @Test
    public void testIkeSessionParamsEncodeDecodeIsLossLess() throws Exception {
        IkeSessionParams sessionParams = buildWithPskCommon(REMOTE_IPV4_HOST_ADDRESS).build();

        PersistableBundle bundle = sessionParams.toPersistableBundle();
        IkeSessionParams result = IkeSessionParams.fromPersistableBundle(bundle, mMockContext);

        assertEquals(sessionParams, result);
    }

    @Test(expected = IllegalStateException.class)
    public void testEncodeIkeSessionParamsWithConfiguredNetwork() throws Exception {
        IkeSessionParams sessionParams =
                buildWithPskCommon(REMOTE_IPV4_HOST_ADDRESS)
                        .setConfiguredNetwork(mMockUserConfigNetwork)
                        .build();

        PersistableBundle bundle = sessionParams.toPersistableBundle();
    }

    @Test(expected = IllegalStateException.class)
    public void testEncodeIkeSessionParamsWith3gppExtension() throws Exception {
        Ike3gppExtension ike3gppExtension =
                new Ike3gppExtension(
                        new Ike3gppParams.Builder().build(), mock(Ike3gppDataListener.class));

        IkeSessionParams sessionParams =
                buildWithPskCommon(REMOTE_IPV4_HOST_ADDRESS)
                        .setIke3gppExtension(ike3gppExtension)
                        .build();

        PersistableBundle bundle = sessionParams.toPersistableBundle();
    }

    @Test
    public void testAddInvalidIkeOption() throws Exception {
        try {
            new IkeSessionParams.Builder(mMockConnectManager).addIkeOption(IKE_OPTION_INVALID);
            fail("Expected to fail due to invalid ikeOption");
        } catch (IllegalArgumentException expected) {
        }
    }

    @Test
    public void testRemoveInvalidIkeOption() throws Exception {
        try {
            new IkeSessionParams.Builder(mMockConnectManager).removeIkeOption(IKE_OPTION_INVALID);
            fail("Expected to fail due to invalid ikeOption");
        } catch (IllegalArgumentException expected) {
        }
    }

    @Test
    public void testCheckInvalidIkeOption() throws Exception {
        IkeSessionParams sessionParams =
                buildWithPskCommon(REMOTE_IPV4_HOST_ADDRESS)
                        .addIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID)
                        .build();

        try {
            sessionParams.hasIkeOption(IKE_OPTION_INVALID);
            fail("Expected to fail due to invalid ikeOption");
        } catch (IllegalArgumentException expected) {
        }
    }

    @Test
    public void testBuildWithPskAndDpdDelay() throws Exception {
        final int dpdDelaySec = 100;

        IkeSessionParams sessionParams =
                buildWithPskCommon(REMOTE_IPV4_HOST_ADDRESS)
                        .setDpdDelaySeconds(dpdDelaySec)
                        .build();

        verifyIkeSessionParamsCommon(sessionParams);
        verifyAuthPskConfig(sessionParams);
        assertEquals(REMOTE_IPV4_HOST_ADDRESS, sessionParams.getServerHostname());

        // Verify default values
        assertFalse(sessionParams.hasIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID));
        assertArrayEquals(
                IKE_RETRANS_TIMEOUT_MS_LIST_DEFAULT,
                sessionParams.getRetransmissionTimeoutsMillis());

        // Verify DPD delay
        assertEquals(dpdDelaySec, sessionParams.getDpdDelaySeconds());
    }

    @Test
    public void testBuildWithInvalidDpdDelay() throws Exception {
        final int invalidDpdDelay = 1;
        try {
            new IkeSessionParams.Builder(mMockConnectManager).setDpdDelaySeconds(invalidDpdDelay);
            fail("Expected to fail due to invalid DPD delay");
        } catch (IllegalArgumentException expected) {
        }
    }

    @Test
    public void testBuildWithPskAndNattKeepaliveDelay() throws Exception {
        final int nattKeepaliveDelay = 100;

        IkeSessionParams sessionParams =
                buildWithPskCommon(REMOTE_IPV4_HOST_ADDRESS)
                        .setNattKeepAliveDelaySeconds(nattKeepaliveDelay)
                        .build();

        // Verify NATT keepalive delay
        assertEquals(nattKeepaliveDelay, sessionParams.getNattKeepAliveDelaySeconds());
    }

    @Test
    public void testNattKeepaliveRange() {
        assertTrue(
                SocketKeepalive.MIN_INTERVAL_SEC
                        <= IkeSessionParams.IKE_NATT_KEEPALIVE_DELAY_SEC_MIN);
        assertTrue(
                SocketKeepalive.MAX_INTERVAL_SEC
                        >= IkeSessionParams.IKE_NATT_KEEPALIVE_DELAY_SEC_MAX);
    }

    @Test(expected = IllegalArgumentException.class)
    public void testBuildWithNattKeepaliveDelayTooShort() throws Exception {
        final int lowNattKeepaliveDelay = 1;
        new IkeSessionParams.Builder(mMockConnectManager)
                .setNattKeepAliveDelaySeconds(lowNattKeepaliveDelay);
    }

    @Test(expected = IllegalArgumentException.class)
    public void testBuildWithNattKeepaliveDelayTooLong() throws Exception {
        final int highNattKeepaliveDelay = 9999;
        new IkeSessionParams.Builder(mMockConnectManager)
                .setNattKeepAliveDelaySeconds(highNattKeepaliveDelay);
    }

    @Test
    public void testBuildWithPskAndRetransmission() throws Exception {
        final int[] retransmissionTimeoutList = new int[] {1000, 2000, 3000, 4000};

        IkeSessionParams sessionParams =
                buildWithPskCommon(REMOTE_IPV4_HOST_ADDRESS)
                        .setRetransmissionTimeoutsMillis(retransmissionTimeoutList)
                        .build();

        verifyIkeSessionParamsCommon(sessionParams);
        verifyAuthPskConfig(sessionParams);
        assertEquals(REMOTE_IPV4_HOST_ADDRESS, sessionParams.getServerHostname());

        // Verify default values
        assertEquals(IKE_DPD_DELAY_SEC_DEFAULT, sessionParams.getDpdDelaySeconds());
        assertFalse(sessionParams.hasIkeOption(IKE_OPTION_ACCEPT_ANY_REMOTE_ID));

        // Verify retransmission configuration
        assertEquals(retransmissionTimeoutList, sessionParams.getRetransmissionTimeoutsMillis());
    }

    @Test
    public void testBuildWithInvalidRetransmissionTimeout() throws Exception {
        final int[] invalidRetransTimeoutMsList = new int[] {1000, 2000, 3000, Integer.MAX_VALUE};
        try {
            new IkeSessionParams.Builder(mMockConnectManager)
                    .setRetransmissionTimeoutsMillis(invalidRetransTimeoutMsList);
            fail("Expected to fail due to invalid retransmission timeout");
        } catch (IllegalArgumentException expected) {
        }
    }

    @Test
    public void testBuildWithInvalidMaxRetransmissionAttempts() throws Exception {
        final int[] invalidRetransTimeoutMsList = new int[20];
        for (int t : invalidRetransTimeoutMsList) t = 500;

        try {
            new IkeSessionParams.Builder(mMockConnectManager)
                    .setRetransmissionTimeoutsMillis(invalidRetransTimeoutMsList);
            fail("Expected to fail due to invalid max retransmission times");
        } catch (IllegalArgumentException expected) {
        }
    }

    @Test
    public void testBuildWithEap() throws Exception {
        EapSessionConfig eapConfig = mock(EapSessionConfig.class);

        IkeSessionParams sessionParams =
                new IkeSessionParams.Builder(mMockConnectManager)
                        .setServerHostname(REMOTE_IPV4_HOST_ADDRESS)
                        .addSaProposal(mIkeSaProposal)
                        .setLocalIdentification(mLocalIdentification)
                        .setRemoteIdentification(mRemoteIdentification)
                        .setAuthEap(mMockServerCaCert, eapConfig)
                        .build();

        verifyIkeParamsWithSeverIpAndDefaultValues(sessionParams);
        assertEquals(mMockDefaultNetwork, sessionParams.getNetwork());
        assertNull(sessionParams.getConfiguredNetwork());

        IkeAuthConfig localConfig = sessionParams.getLocalAuthConfig();
        assertTrue(localConfig instanceof IkeAuthEapConfig);
        assertEquals(IkeSessionParams.IKE_AUTH_METHOD_EAP, localConfig.mAuthMethod);
        assertEquals(eapConfig, ((IkeAuthEapConfig) localConfig).mEapConfig);

        IkeAuthConfig remoteConfig = sessionParams.getRemoteAuthConfig();
        assertTrue(remoteConfig instanceof IkeAuthDigitalSignRemoteConfig);
        assertEquals(IkeSessionParams.IKE_AUTH_METHOD_PUB_KEY_SIGNATURE, remoteConfig.mAuthMethod);
        assertEquals(
                mMockServerCaCert,
                ((IkeAuthDigitalSignRemoteConfig) remoteConfig).mTrustAnchor.getTrustedCert());
    }

    @Test
    public void testBuildWithDigitalSignatureAuth() throws Exception {
        IkeSessionParams sessionParams =
                new IkeSessionParams.Builder(mMockConnectManager)
                        .setServerHostname(REMOTE_IPV4_HOST_ADDRESS)
                        .setNetwork(mMockUserConfigNetwork)
                        .addSaProposal(mIkeSaProposal)
                        .setLocalIdentification(mLocalIdentification)
                        .setRemoteIdentification(mRemoteIdentification)
                        .setAuthDigitalSignature(
                                mMockServerCaCert, mMockClientEndCert, mMockRsaPrivateKey)
                        .build();

        verifyIkeParamsWithSeverIpAndDefaultValues(sessionParams);
        assertEquals(mMockUserConfigNetwork, sessionParams.getNetwork());
        assertEquals(mMockUserConfigNetwork, sessionParams.getConfiguredNetwork());

        IkeAuthConfig localConfig = sessionParams.getLocalAuthConfig();
        assertTrue(localConfig instanceof IkeAuthDigitalSignLocalConfig);

        IkeAuthDigitalSignLocalConfig localAuthConfig = (IkeAuthDigitalSignLocalConfig) localConfig;
        assertEquals(
                IkeSessionParams.IKE_AUTH_METHOD_PUB_KEY_SIGNATURE, localAuthConfig.mAuthMethod);
        assertEquals(mMockClientEndCert, localAuthConfig.mEndCert);
        assertTrue(localAuthConfig.mIntermediateCerts.isEmpty());
        assertEquals(mMockRsaPrivateKey, localAuthConfig.mPrivateKey);

        IkeAuthConfig remoteConfig = sessionParams.getRemoteAuthConfig();
        assertTrue(remoteConfig instanceof IkeAuthDigitalSignRemoteConfig);
        assertEquals(IkeSessionParams.IKE_AUTH_METHOD_PUB_KEY_SIGNATURE, remoteConfig.mAuthMethod);
        assertEquals(
                mMockServerCaCert,
                ((IkeAuthDigitalSignRemoteConfig) remoteConfig).mTrustAnchor.getTrustedCert());
    }

    @Test
    public void testBuildWithDsaDigitalSignatureAuth() throws Exception {
        try {
            IkeSessionParams sessionParams =
                    new IkeSessionParams.Builder(mMockConnectManager)
                            .setServerHostname(REMOTE_IPV4_HOST_ADDRESS)
                            .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) {

        }
    }

    private void verifyAttrTypes(SparseArray expectedAttrCntMap, IkeSessionParams ikeParams) {
        ConfigAttribute[] configAttributes = ikeParams.getConfigurationAttributesInternal();

        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 testBuildWithPcscfAddress() throws Exception {
        IkeSessionParams sessionParams =
                new IkeSessionParams.Builder(mMockConnectManager)
                        .setServerHostname(REMOTE_IPV4_HOST_ADDRESS)
                        .addSaProposal(mIkeSaProposal)
                        .setLocalIdentification(mLocalIdentification)
                        .setRemoteIdentification(mRemoteIdentification)
                        .setAuthPsk(PSK)
                        .addPcscfServerRequest(AF_INET)
                        .addPcscfServerRequest(PCSCF_IPV4_ADDRESS_1)
                        .addPcscfServerRequest(PCSCF_IPV6_ADDRESS_2)
                        .addPcscfServerRequest(AF_INET6)
                        .addPcscfServerRequest(PCSCF_IPV4_ADDRESS_1)
                        .addPcscfServerRequest(PCSCF_IPV6_ADDRESS_2)
                        .build();

        SparseArray<Integer> expectedAttrCounts = new SparseArray<>();
        expectedAttrCounts.put(CONFIG_ATTR_IP4_PCSCF, 3);
        expectedAttrCounts.put(CONFIG_ATTR_IP6_PCSCF, 3);

        verifyAttrTypes(expectedAttrCounts, sessionParams);
    }

    @Test
    public void testBuildWithoutPcscfAddress() throws Exception {
        IkeSessionParams sessionParams =
                new IkeSessionParams.Builder(mMockConnectManager)
                        .setServerHostname(REMOTE_IPV4_HOST_ADDRESS)
                        .addSaProposal(mIkeSaProposal)
                        .setLocalIdentification(mLocalIdentification)
                        .setRemoteIdentification(mRemoteIdentification)
                        .setAuthPsk(PSK)
                        .build();

        SparseArray<Integer> expectedAttrCounts = new SparseArray<>();

        verifyAttrTypes(expectedAttrCounts, sessionParams);
    }

    @Test
    public void testBuildWithoutSaProposal() throws Exception {
        try {
            new IkeSessionParams.Builder(mMockConnectManager)
                    .setServerHostname(REMOTE_IPV4_HOST_ADDRESS)
                    .build();
            fail("Expected to fail due to absence of SA proposal.");
        } catch (IllegalArgumentException expected) {
        }
    }

    @Test
    public void testBuildWithoutLocalId() throws Exception {
        try {
            new IkeSessionParams.Builder(mMockConnectManager)
                    .setServerHostname(REMOTE_IPV4_HOST_ADDRESS)
                    .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 IkeSessionParams.Builder(mMockConnectManager)
                    .setServerHostname(REMOTE_IPV4_HOST_ADDRESS)
                    .addSaProposal(mIkeSaProposal)
                    .setLocalIdentification(mLocalIdentification)
                    .setRemoteIdentification(mRemoteIdentification)
                    .build();
            fail("Expected to fail because authentiction method is not set.");
        } catch (IllegalArgumentException expected) {
        }
    }

    @Test
    public void testNonAsciiFqdnAuthentication() throws Exception {
        try {
            new IkeFqdnIdentification("¯\\_(ツ)_/¯");
            fail("Expected failure based on non-ASCII characters.");
        } catch (IllegalArgumentException expected) {
        }
    }

    @Test
    public void testSetHardLifetimeTooLong() throws Exception {
        try {
            new IkeSessionParams.Builder(mMockConnectManager)
                    .setLifetimeSeconds(
                            IKE_HARD_LIFETIME_SEC_MAXIMUM + 1, IKE_SOFT_LIFETIME_SEC_DEFAULT);
            fail("Expected failure because hard lifetime is too long");
        } catch (IllegalArgumentException expected) {
        }
    }

    @Test
    public void testSetHardLifetimeTooShort() throws Exception {
        try {
            new IkeSessionParams.Builder(mMockConnectManager)
                    .setLifetimeSeconds(
                            IKE_HARD_LIFETIME_SEC_MINIMUM - 1, IKE_SOFT_LIFETIME_SEC_DEFAULT);
            fail("Expected failure because hard lifetime is too short");
        } catch (IllegalArgumentException expected) {
        }
    }

    @Test
    public void testSetSoftLifetimeTooLong() throws Exception {
        try {
            new IkeSessionParams.Builder(mMockConnectManager)
                    .setLifetimeSeconds(
                            IKE_HARD_LIFETIME_SEC_DEFAULT, IKE_HARD_LIFETIME_SEC_DEFAULT);
            fail("Expected failure because soft lifetime is too long");
        } catch (IllegalArgumentException expected) {
        }
    }

    @Test
    public void testSetSoftLifetimeTooShort() throws Exception {
        try {
            new IkeSessionParams.Builder(mMockConnectManager)
                    .setLifetimeSeconds(IKE_HARD_LIFETIME_SEC_DEFAULT, 0);
            fail("Expected failure because soft lifetime is too short");
        } catch (IllegalArgumentException expected) {
        }
    }

    @Test
    public void testExpceptionOnEapOnlyOptionWithoutEapAuth() throws Exception {
        try {
            IkeSessionParams sessionParams =
                    buildWithPskCommon(REMOTE_IPV4_HOST_ADDRESS)
                            .addIkeOption(IKE_OPTION_EAP_ONLY_AUTH)
                            .build();
            fail("Expected failure because eap only option added without setting auth config");
        } catch (IllegalArgumentException expected) {

        }
    }

    @Test
    public void testExceptionOnEapOnlyOptionWithEapOnlyUnsafeMethod() throws Exception {
        try {
            EapSessionConfig eapSessionConfig =
                    new EapSessionConfig.Builder()
                            .setEapMsChapV2Config(EAP_MSCHAP_V2_USERNAME, EAP_MSCHAP_V2_PASSWORD)
                            .setEapAkaConfig(0, 0)
                            .build();

            IkeSessionParams sessionParams =
                    buildWithPskCommon(REMOTE_IPV4_HOST_ADDRESS)
                            .addIkeOption(IKE_OPTION_EAP_ONLY_AUTH)
                            .setAuthEap(null, eapSessionConfig)
                            .build();
            fail("Expected failure because eap only option added without eap only safe method");
        } catch (IllegalArgumentException expected) {

        }
    }

    @Test
    public void testBuildWithEapOnlyOption() throws Exception {
        EapSessionConfig eapSessionConfig = new EapSessionConfig.Builder()
                .setEapAkaConfig(0, TelephonyManager.APPTYPE_ISIM)
                .build();

        IkeSessionParams sessionParams = buildWithPskCommon(REMOTE_IPV4_HOST_ADDRESS)
                .addIkeOption(IKE_OPTION_EAP_ONLY_AUTH)
                .setAuthEap(null, eapSessionConfig)
                .build();

        assertNotNull(sessionParams);
        verifyIkeSessionParamsCommon(sessionParams);
        assertTrue(sessionParams.hasIkeOption(IKE_OPTION_EAP_ONLY_AUTH));
        IkeAuthConfig localConfig = sessionParams.getLocalAuthConfig();
        assertTrue(localConfig instanceof IkeAuthEapConfig);
    }

    @Test
    public void testBuildWithIke3gppExtension() throws Exception {
        Ike3gppExtension ike3gppExtension =
                new Ike3gppExtension(
                        new Ike3gppParams.Builder().build(), mock(Ike3gppDataListener.class));

        IkeSessionParams sessionParams =
                buildWithPskCommon(REMOTE_IPV4_HOST_ADDRESS)
                        .setIke3gppExtension(ike3gppExtension)
                        .build();
        assertEquals(ike3gppExtension, sessionParams.getIke3gppExtension());
    }

    private static void verifyPersistableBundleEncodeDecodeIsLossless(IkeAuthConfig config) {
        PersistableBundle bundle = config.toPersistableBundle();
        IkeAuthConfig result = IkeAuthConfig.fromPersistableBundle(bundle);

        assertEquals(config, result);
    }

    @Test
    public void testPersistableBundleEncodeDecodePskAuth() {
        verifyPersistableBundleEncodeDecodeIsLossless(new IkeAuthPskConfig(PSK));
    }

    @Test
    public void testPersistableBundleEncodeDecodeAuthDigitalSignRemote() throws Exception {
        X509Certificate caCert = CertUtils.createCertFromPemFile("self-signed-ca-b.pem");
        verifyPersistableBundleEncodeDecodeIsLossless(new IkeAuthDigitalSignRemoteConfig(caCert));
    }

    @Test
    public void testPersistableBundleEncodeDecodeAuthDigitalSignRemoteWithoutCaCert()
            throws Exception {
        verifyPersistableBundleEncodeDecodeIsLossless(new IkeAuthDigitalSignRemoteConfig(null));
    }

    @Test
    public void testEqualsAuthConfigDigitalSignRemote() throws Exception {
        X509Certificate caCert = CertUtils.createCertFromPemFile("self-signed-ca-b.pem");
        assertEquals(
                new IkeAuthDigitalSignRemoteConfig(caCert),
                new IkeAuthDigitalSignRemoteConfig(caCert));
        assertEquals(
                new IkeAuthDigitalSignRemoteConfig(null), new IkeAuthDigitalSignRemoteConfig(null));
        assertNotEquals(
                new IkeAuthDigitalSignRemoteConfig(caCert),
                new IkeAuthDigitalSignRemoteConfig(null));
    }

    @Test
    public void testPersistableBundleEncodeDecodeAuthDigitalSignLocal() throws Exception {
        X509Certificate endCert = CertUtils.createCertFromPemFile("end-cert-b.pem");
        X509Certificate intermediateCertOne =
                CertUtils.createCertFromPemFile("intermediate-ca-b-one.pem");
        X509Certificate intermediateCertTwo =
                CertUtils.createCertFromPemFile("intermediate-ca-b-two.pem");
        PrivateKey key = CertUtils.createRsaPrivateKeyFromKeyFile("end-cert-key-a.key");

        verifyPersistableBundleEncodeDecodeIsLossless(
                new IkeAuthDigitalSignLocalConfig(
                        endCert, Arrays.asList(intermediateCertOne, intermediateCertTwo), key));
    }

    @Test
    public void testPersistableBundleEncodeDecodeAuthEap() {
        EapSessionConfig eapSessionConfig =
                new EapSessionConfig.Builder()
                        .setEapAkaConfig(SUB_ID, TelephonyManager.APPTYPE_ISIM)
                        .build();
        verifyPersistableBundleEncodeDecodeIsLossless(new IkeAuthEapConfig(eapSessionConfig));
    }
}
