Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c4fbd6a9 authored by Yan Yan's avatar Yan Yan
Browse files

Create VcnControlPlaneConfig and VcnControlPlaneIkeConfig

VcnControlPlaneConfig contains control plane configuration for
a VCN gateway connection. VcnControlPlaneIkeConfig is a
subclass that contains IKE configuration.

The followup CL will store VcnControlPlaneConfig in
VcnGatewayConnectionConfig.

Bug: 163604823
Test: FrameworksVcnTests(new tests added)
Change-Id: If7a85ae44e77fc4477b56ffa50c6e99ee96132d0
parent ec9f1c68
Loading
Loading
Loading
Loading
+107 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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.vcn;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.os.PersistableBundle;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Objects;

/**
 * This class represents a control plane configuration for a Virtual Carrier Network connection.
 *
 * <p>Each {@link VcnGatewayConnectionConfig} must have a {@link VcnControlPlaneConfig}, containing
 * all connection, authentication and authorization parameters required to establish a Gateway
 * Connection with a remote endpoint.
 *
 * <p>A {@link VcnControlPlaneConfig} object can be shared by multiple {@link
 * VcnGatewayConnectionConfig}(s) if they will used for connecting with the same remote endpoint.
 *
 * @see VcnManager
 * @see VcnGatewayConnectionConfig
 *
 * @hide
 */
public abstract class VcnControlPlaneConfig {
    /** @hide */
    @Retention(RetentionPolicy.SOURCE)
    @IntDef({CONFIG_TYPE_IKE})
    public @interface ConfigType {}

    /** @hide */
    public static final int CONFIG_TYPE_IKE = 1;

    private static final String CONFIG_TYPE_KEY = "mConfigType";
    @ConfigType private final int mConfigType;

    /**
     * Package private constructor.
     *
     * @hide
     */
    VcnControlPlaneConfig(int configType) {
        mConfigType = configType;
    }

    /**
     * Constructs a VcnControlPlaneConfig object by deserializing a PersistableBundle.
     *
     * @param in the {@link PersistableBundle} containing an {@link VcnControlPlaneConfig} object
     * @hide
     */
    public static VcnControlPlaneConfig fromPersistableBundle(@NonNull PersistableBundle in) {
        Objects.requireNonNull(in, "PersistableBundle was null");

        int configType = in.getInt(CONFIG_TYPE_KEY);
        switch (configType) {
            case CONFIG_TYPE_IKE:
                return new VcnControlPlaneIkeConfig(in);
            default:
                throw new IllegalStateException("Unrecognized configType: " + configType);
        }
    }

    /**
     * Converts this VcnControlPlaneConfig to a PersistableBundle.
     *
     * @hide
     */
    @NonNull
    public PersistableBundle toPersistableBundle() {
        final PersistableBundle result = new PersistableBundle();
        result.putInt(CONFIG_TYPE_KEY, mConfigType);
        return result;
    }

    /** @hide */
    @Override
    public int hashCode() {
        return Objects.hash(mConfigType);
    }

    /** @hide */
    @Override
    public boolean equals(Object o) {
        if (!(o instanceof VcnControlPlaneConfig)) {
            return false;
        }

        return mConfigType == ((VcnControlPlaneConfig) o).mConfigType;
    }
}
+142 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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.vcn;

import static android.net.vcn.VcnControlPlaneConfig.CONFIG_TYPE_IKE;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.net.ipsec.ike.IkeSessionParams;
import android.net.ipsec.ike.TunnelModeChildSessionParams;
import android.os.PersistableBundle;
import android.util.ArraySet;

import java.util.Objects;

/**
 * This class is an IKEv2 control plane configuration for a Virtual Carrier Network connection.
 *
 * <p>This class is an extension of the {@link VcnControlPlaneConfig}, containing IKEv2-specific
 * configuration, authentication and authorization parameters.
 *
 * @see VcnControlPlaneConfig
 *
 * @hide
 */
public final class VcnControlPlaneIkeConfig extends VcnControlPlaneConfig {
    private static final String TAG = VcnControlPlaneIkeConfig.class.getSimpleName();

    // STOPSHIP: b/163604823 Make mIkeParams and mChildParams @NonNull when it is supported to
    // construct mIkeParams and mChildParams from PersistableBundles.

    private static final String IKE_PARAMS_KEY = "mIkeParams";
    @Nullable private final IkeSessionParams mIkeParams;

    private static final String CHILD_PARAMS_KEY = "mChildParams";
    @Nullable private final TunnelModeChildSessionParams mChildParams;

    private static final ArraySet<String> BUNDLE_KEY_SET = new ArraySet<>();

    {
        BUNDLE_KEY_SET.add(IKE_PARAMS_KEY);
        BUNDLE_KEY_SET.add(CHILD_PARAMS_KEY);
    }

    /**
     * Constructs a VcnControlPlaneIkeConfig object.
     *
     * @param ikeParams the IKE Session negotiation parameters
     * @param childParams the tunnel mode Child Session negotiation parameters
     */
    public VcnControlPlaneIkeConfig(
            @NonNull IkeSessionParams ikeParams,
            @NonNull TunnelModeChildSessionParams childParams) {
        super(CONFIG_TYPE_IKE);
        mIkeParams = ikeParams;
        mChildParams = childParams;
        validate();
    }

    /**
     * Constructs a VcnControlPlaneIkeConfig object by deserializing a PersistableBundle.
     *
     * @param in the {@link PersistableBundle} containing an {@link VcnControlPlaneIkeConfig} object
     * @hide
     */
    public VcnControlPlaneIkeConfig(@NonNull PersistableBundle in) {
        super(CONFIG_TYPE_IKE);
        final PersistableBundle ikeParamsBundle = in.getPersistableBundle(IKE_PARAMS_KEY);
        final PersistableBundle childParamsBundle = in.getPersistableBundle(CHILD_PARAMS_KEY);

        // STOPSHIP: b/163604823 Support constructing mIkeParams and mChildParams from
        // PersistableBundles.

        mIkeParams = null;
        mChildParams = null;
    }

    private void validate() {
        Objects.requireNonNull(mIkeParams, "mIkeParams was null");
        Objects.requireNonNull(mChildParams, "mChildParams was null");
    }

    /**
     * Converts this VcnControlPlaneConfig to a PersistableBundle.
     *
     * @hide
     */
    @Override
    @NonNull
    public PersistableBundle toPersistableBundle() {
        final PersistableBundle result = super.toPersistableBundle();

        // STOPSHIP: b/163604823 Support converting mIkeParams and mChildParams to
        // PersistableBundles.
        return result;
    }

    /** Retrieves the IKE Session configuration. */
    @NonNull
    public IkeSessionParams getIkeSessionParams() {
        return mIkeParams;
    }

    /** Retrieves the tunnel mode Child Session configuration. */
    @NonNull
    public TunnelModeChildSessionParams getChildSessionParams() {
        return mChildParams;
    }

    /** @hide */
    @Override
    public int hashCode() {
        return Objects.hash(super.hashCode(), mIkeParams, mChildParams);
    }

    /** @hide */
    @Override
    public boolean equals(Object o) {
        if (!(o instanceof VcnControlPlaneIkeConfig)) {
            return false;
        }

        VcnControlPlaneIkeConfig other = (VcnControlPlaneIkeConfig) o;
        return super.equals(o)
                && Objects.equals(mIkeParams, other.mIkeParams)
                && Objects.equals(mChildParams, other.mChildParams);
    }
}
+118 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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.vcn;

import static android.net.ipsec.ike.SaProposal.DH_GROUP_2048_BIT_MODP;
import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12;
import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.ipsec.ike.ChildSaProposal;
import android.net.ipsec.ike.IkeFqdnIdentification;
import android.net.ipsec.ike.IkeSaProposal;
import android.net.ipsec.ike.IkeSessionParams;
import android.net.ipsec.ike.SaProposal;
import android.net.ipsec.ike.TunnelModeChildSessionParams;

import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;

import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(AndroidJUnit4.class)
@SmallTest
public class VcnControlPlaneIkeConfigTest {
    private static final IkeSessionParams IKE_PARAMS;
    private static final TunnelModeChildSessionParams CHILD_PARAMS;

    static {
        IkeSaProposal ikeProposal =
                new IkeSaProposal.Builder()
                        .addEncryptionAlgorithm(
                                ENCRYPTION_ALGORITHM_AES_GCM_12, SaProposal.KEY_LEN_AES_128)
                        .addDhGroup(DH_GROUP_2048_BIT_MODP)
                        .addPseudorandomFunction(PSEUDORANDOM_FUNCTION_AES128_XCBC)
                        .build();

        Context mockContext = mock(Context.class);
        ConnectivityManager mockConnectManager = mock(ConnectivityManager.class);
        doReturn(mockConnectManager)
                .when(mockContext)
                .getSystemService(Context.CONNECTIVITY_SERVICE);
        doReturn(mock(Network.class)).when(mockConnectManager).getActiveNetwork();

        final String serverHostname = "192.0.2.100";
        final String testLocalId = "test.client.com";
        final String testRemoteId = "test.server.com";
        final byte[] psk = "psk".getBytes();

        IKE_PARAMS =
                new IkeSessionParams.Builder(mockContext)
                        .setServerHostname(serverHostname)
                        .addSaProposal(ikeProposal)
                        .setLocalIdentification(new IkeFqdnIdentification(testLocalId))
                        .setRemoteIdentification(new IkeFqdnIdentification(testRemoteId))
                        .setAuthPsk(psk)
                        .build();

        ChildSaProposal childProposal =
                new ChildSaProposal.Builder()
                        .addEncryptionAlgorithm(
                                ENCRYPTION_ALGORITHM_AES_GCM_12, SaProposal.KEY_LEN_AES_128)
                        .build();
        CHILD_PARAMS =
                new TunnelModeChildSessionParams.Builder().addSaProposal(childProposal).build();
    }

    // Package private for use in VcnGatewayConnectionConfigTest
    static VcnControlPlaneIkeConfig buildTestConfig() {
        return new VcnControlPlaneIkeConfig(IKE_PARAMS, CHILD_PARAMS);
    }

    @Test
    public void testGetters() {
        final VcnControlPlaneIkeConfig config = buildTestConfig();
        assertEquals(IKE_PARAMS, config.getIkeSessionParams());
        assertEquals(CHILD_PARAMS, config.getChildSessionParams());
    }

    @Test
    public void testConstructConfigWithoutIkeParams() {
        try {
            new VcnControlPlaneIkeConfig(null, CHILD_PARAMS);
            fail("Expect to fail because ikeParams was null");
        } catch (NullPointerException expected) {
        }
    }

    @Test
    public void testBuilderConfigWithoutChildParams() {
        try {
            new VcnControlPlaneIkeConfig(IKE_PARAMS, null);
            fail("Expect to fail because childParams was null");
        } catch (NullPointerException expected) {
        }
    }
}