Support converting IkeAuthConfig to/from PersistableBundle
Bug: 163604823 Test: FrameworksVcnTests(add new tests) Change-Id: I97d9a7db423711dbccea412b96f069fe1dbd2779
This commit is contained in:
@@ -21,11 +21,14 @@ import static com.android.internal.annotations.VisibleForTesting.Visibility;
|
||||
import android.annotation.NonNull;
|
||||
import android.net.ipsec.ike.IkeSaProposal;
|
||||
import android.net.ipsec.ike.IkeSessionParams;
|
||||
import android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig;
|
||||
import android.net.ipsec.ike.IkeSessionParams.IkeAuthPskConfig;
|
||||
import android.os.PersistableBundle;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.server.vcn.util.PersistableBundleUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@@ -40,6 +43,8 @@ public final class IkeSessionParamsUtils {
|
||||
private static final String SA_PROPOSALS_KEY = "SA_PROPOSALS_KEY";
|
||||
private static final String LOCAL_ID_KEY = "LOCAL_ID_KEY";
|
||||
private static final String REMOTE_ID_KEY = "REMOTE_ID_KEY";
|
||||
private static final String LOCAL_AUTH_KEY = "LOCAL_AUTH_KEY";
|
||||
private static final String REMOTE_AUTH_KEY = "REMOTE_AUTH_KEY";
|
||||
private static final String RETRANS_TIMEOUTS_KEY = "RETRANS_TIMEOUTS_KEY";
|
||||
private static final String HARD_LIFETIME_SEC_KEY = "HARD_LIFETIME_SEC_KEY";
|
||||
private static final String SOFT_LIFETIME_SEC_KEY = "SOFT_LIFETIME_SEC_KEY";
|
||||
@@ -71,13 +76,18 @@ public final class IkeSessionParamsUtils {
|
||||
REMOTE_ID_KEY,
|
||||
IkeIdentificationUtils.toPersistableBundle(params.getRemoteIdentification()));
|
||||
|
||||
result.putPersistableBundle(
|
||||
LOCAL_AUTH_KEY, AuthConfigUtils.toPersistableBundle(params.getLocalAuthConfig()));
|
||||
result.putPersistableBundle(
|
||||
REMOTE_AUTH_KEY, AuthConfigUtils.toPersistableBundle(params.getRemoteAuthConfig()));
|
||||
|
||||
result.putIntArray(RETRANS_TIMEOUTS_KEY, params.getRetransmissionTimeoutsMillis());
|
||||
result.putInt(HARD_LIFETIME_SEC_KEY, params.getHardLifetimeSeconds());
|
||||
result.putInt(SOFT_LIFETIME_SEC_KEY, params.getSoftLifetimeSeconds());
|
||||
result.putInt(DPD_DELAY_SEC_KEY, params.getDpdDelaySeconds());
|
||||
result.putInt(NATT_KEEPALIVE_DELAY_SEC_KEY, params.getNattKeepAliveDelaySeconds());
|
||||
|
||||
// TODO: Handle authentication configuration, configuration requests and IKE options.
|
||||
// TODO: Handle configuration requests and IKE options.
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -107,14 +117,105 @@ public final class IkeSessionParamsUtils {
|
||||
IkeIdentificationUtils.fromPersistableBundle(
|
||||
in.getPersistableBundle(REMOTE_ID_KEY)));
|
||||
|
||||
AuthConfigUtils.setBuilderByReadingPersistableBundle(
|
||||
in.getPersistableBundle(LOCAL_AUTH_KEY),
|
||||
in.getPersistableBundle(REMOTE_AUTH_KEY),
|
||||
builder);
|
||||
|
||||
builder.setRetransmissionTimeoutsMillis(in.getIntArray(RETRANS_TIMEOUTS_KEY));
|
||||
builder.setLifetimeSeconds(
|
||||
in.getInt(HARD_LIFETIME_SEC_KEY), in.getInt(SOFT_LIFETIME_SEC_KEY));
|
||||
builder.setDpdDelaySeconds(in.getInt(DPD_DELAY_SEC_KEY));
|
||||
builder.setNattKeepAliveDelaySeconds(in.getInt(NATT_KEEPALIVE_DELAY_SEC_KEY));
|
||||
|
||||
// TODO: Handle authentication configuration, configuration requests and IKE options.
|
||||
// TODO: Handle configuration requests and IKE options.
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private static final class AuthConfigUtils {
|
||||
private static final int IKE_AUTH_METHOD_PSK = 1;
|
||||
private static final int IKE_AUTH_METHOD_PUB_KEY_SIGNATURE = 2;
|
||||
private static final int IKE_AUTH_METHOD_EAP = 3;
|
||||
|
||||
private static final String AUTH_METHOD_KEY = "AUTH_METHOD_KEY";
|
||||
|
||||
@NonNull
|
||||
public static PersistableBundle toPersistableBundle(@NonNull IkeAuthConfig authConfig) {
|
||||
if (authConfig instanceof IkeAuthPskConfig) {
|
||||
IkeAuthPskConfig config = (IkeAuthPskConfig) authConfig;
|
||||
return IkeAuthPskConfigUtils.toPersistableBundle(
|
||||
config, createPersistableBundle(IKE_AUTH_METHOD_PSK));
|
||||
} else {
|
||||
throw new IllegalStateException("Invalid IkeAuthConfig subclass");
|
||||
}
|
||||
|
||||
// TODO: Handle EAP auth and digital signature based auth.
|
||||
}
|
||||
|
||||
private static PersistableBundle createPersistableBundle(int type) {
|
||||
final PersistableBundle result = new PersistableBundle();
|
||||
result.putInt(AUTH_METHOD_KEY, type);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void setBuilderByReadingPersistableBundle(
|
||||
@NonNull PersistableBundle localAuthBundle,
|
||||
@NonNull PersistableBundle remoteAuthBundle,
|
||||
@NonNull IkeSessionParams.Builder builder) {
|
||||
Objects.requireNonNull(localAuthBundle, "localAuthBundle was null");
|
||||
Objects.requireNonNull(remoteAuthBundle, "remoteAuthBundle was null");
|
||||
|
||||
final int localMethodType = localAuthBundle.getInt(AUTH_METHOD_KEY);
|
||||
final int remoteMethodType = remoteAuthBundle.getInt(AUTH_METHOD_KEY);
|
||||
switch (localMethodType) {
|
||||
case IKE_AUTH_METHOD_PSK:
|
||||
if (remoteMethodType != IKE_AUTH_METHOD_PSK) {
|
||||
throw new IllegalArgumentException(
|
||||
"Expect remote auth method to be PSK based, but was "
|
||||
+ remoteMethodType);
|
||||
}
|
||||
IkeAuthPskConfigUtils.setBuilderByReadingPersistableBundle(
|
||||
localAuthBundle, remoteAuthBundle, builder);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid EAP method type " + localMethodType);
|
||||
}
|
||||
// TODO: Handle EAP auth and digital signature based auth.
|
||||
}
|
||||
}
|
||||
|
||||
private static final class IkeAuthPskConfigUtils {
|
||||
private static final String PSK_KEY = "PSK_KEY";
|
||||
|
||||
@NonNull
|
||||
public static PersistableBundle toPersistableBundle(
|
||||
@NonNull IkeAuthPskConfig config, @NonNull PersistableBundle result) {
|
||||
result.putPersistableBundle(
|
||||
PSK_KEY, PersistableBundleUtils.fromByteArray(config.getPsk()));
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void setBuilderByReadingPersistableBundle(
|
||||
@NonNull PersistableBundle localAuthBundle,
|
||||
@NonNull PersistableBundle remoteAuthBundle,
|
||||
@NonNull IkeSessionParams.Builder builder) {
|
||||
Objects.requireNonNull(localAuthBundle, "localAuthBundle was null");
|
||||
Objects.requireNonNull(remoteAuthBundle, "remoteAuthBundle was null");
|
||||
|
||||
final PersistableBundle localPskBundle = localAuthBundle.getPersistableBundle(PSK_KEY);
|
||||
final PersistableBundle remotePskBundle =
|
||||
remoteAuthBundle.getPersistableBundle(PSK_KEY);
|
||||
Objects.requireNonNull(localAuthBundle, "Local PSK was null");
|
||||
Objects.requireNonNull(remoteAuthBundle, "Remote PSK was null");
|
||||
|
||||
final byte[] localPsk = PersistableBundleUtils.toByteArray(localPskBundle);
|
||||
final byte[] remotePsk = PersistableBundleUtils.toByteArray(remotePskBundle);
|
||||
if (!Arrays.equals(localPsk, remotePsk)) {
|
||||
throw new IllegalArgumentException("Local PSK and remote PSK are different");
|
||||
}
|
||||
builder.setAuthPsk(localPsk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* 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.persistablebundleutils;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import android.net.InetAddresses;
|
||||
import android.net.ipsec.ike.IkeFqdnIdentification;
|
||||
import android.net.ipsec.ike.IkeSessionParams;
|
||||
import android.os.PersistableBundle;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class IkeSessionParamsUtilsTest {
|
||||
private static IkeSessionParams.Builder createBuilderMinimum() {
|
||||
final InetAddress serverAddress = InetAddresses.parseNumericAddress("192.0.2.100");
|
||||
|
||||
return new IkeSessionParams.Builder()
|
||||
.setServerHostname(serverAddress.getHostAddress())
|
||||
.addSaProposal(SaProposalUtilsTest.buildTestIkeSaProposal())
|
||||
.setLocalIdentification(new IkeFqdnIdentification("client.test.android.net"))
|
||||
.setRemoteIdentification(new IkeFqdnIdentification("server.test.android.net"))
|
||||
.setAuthPsk("psk".getBytes());
|
||||
}
|
||||
|
||||
private static void verifyPersistableBundleEncodeDecodeIsLossless(IkeSessionParams params) {
|
||||
final PersistableBundle bundle = IkeSessionParamsUtils.toPersistableBundle(params);
|
||||
final IkeSessionParams result = IkeSessionParamsUtils.fromPersistableBundle(bundle);
|
||||
|
||||
assertEquals(result, params);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeRecodeParamsWithLifetimes() throws Exception {
|
||||
final int hardLifetime = (int) TimeUnit.HOURS.toSeconds(20L);
|
||||
final int softLifetime = (int) TimeUnit.HOURS.toSeconds(10L);
|
||||
final IkeSessionParams params =
|
||||
createBuilderMinimum().setLifetimeSeconds(hardLifetime, softLifetime).build();
|
||||
verifyPersistableBundleEncodeDecodeIsLossless(params);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeRecodeParamsWithDpdDelay() throws Exception {
|
||||
final int dpdDelay = (int) TimeUnit.MINUTES.toSeconds(10L);
|
||||
final IkeSessionParams params = createBuilderMinimum().setDpdDelaySeconds(dpdDelay).build();
|
||||
|
||||
verifyPersistableBundleEncodeDecodeIsLossless(params);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeRecodeParamsWithNattKeepalive() throws Exception {
|
||||
final int nattKeepAliveDelay = (int) TimeUnit.MINUTES.toSeconds(5L);
|
||||
final IkeSessionParams params =
|
||||
createBuilderMinimum().setNattKeepAliveDelaySeconds(nattKeepAliveDelay).build();
|
||||
|
||||
verifyPersistableBundleEncodeDecodeIsLossless(params);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeRecodeParamsWithRetransmissionTimeouts() throws Exception {
|
||||
final int[] retransmissionTimeout = new int[] {500, 500, 500, 500, 500, 500};
|
||||
final IkeSessionParams params =
|
||||
createBuilderMinimum()
|
||||
.setRetransmissionTimeoutsMillis(retransmissionTimeout)
|
||||
.build();
|
||||
|
||||
verifyPersistableBundleEncodeDecodeIsLossless(params);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeRecodeParamsWithAuthPsk() throws Exception {
|
||||
final IkeSessionParams params = createBuilderMinimum().setAuthPsk("psk".getBytes()).build();
|
||||
verifyPersistableBundleEncodeDecodeIsLossless(params);
|
||||
}
|
||||
}
|
||||
@@ -32,21 +32,25 @@ import org.junit.runner.RunWith;
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class SaProposalUtilsTest {
|
||||
/** Package private so that IkeSessionParamsUtilsTest can use it */
|
||||
static IkeSaProposal buildTestIkeSaProposal() {
|
||||
return new IkeSaProposal.Builder()
|
||||
.addEncryptionAlgorithm(
|
||||
SaProposal.ENCRYPTION_ALGORITHM_3DES, SaProposal.KEY_LEN_UNUSED)
|
||||
.addEncryptionAlgorithm(
|
||||
SaProposal.ENCRYPTION_ALGORITHM_AES_CBC, SaProposal.KEY_LEN_AES_128)
|
||||
.addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96)
|
||||
.addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128)
|
||||
.addPseudorandomFunction(SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC)
|
||||
.addPseudorandomFunction(SaProposal.PSEUDORANDOM_FUNCTION_SHA2_256)
|
||||
.addDhGroup(SaProposal.DH_GROUP_1024_BIT_MODP)
|
||||
.addDhGroup(SaProposal.DH_GROUP_3072_BIT_MODP)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPersistableBundleEncodeDecodeIsLosslessIkeProposal() throws Exception {
|
||||
final IkeSaProposal proposal =
|
||||
new IkeSaProposal.Builder()
|
||||
.addEncryptionAlgorithm(
|
||||
SaProposal.ENCRYPTION_ALGORITHM_3DES, SaProposal.KEY_LEN_UNUSED)
|
||||
.addEncryptionAlgorithm(
|
||||
SaProposal.ENCRYPTION_ALGORITHM_AES_CBC, SaProposal.KEY_LEN_AES_128)
|
||||
.addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96)
|
||||
.addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128)
|
||||
.addPseudorandomFunction(SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC)
|
||||
.addPseudorandomFunction(SaProposal.PSEUDORANDOM_FUNCTION_SHA2_256)
|
||||
.addDhGroup(SaProposal.DH_GROUP_1024_BIT_MODP)
|
||||
.addDhGroup(SaProposal.DH_GROUP_3072_BIT_MODP)
|
||||
.build();
|
||||
final IkeSaProposal proposal = buildTestIkeSaProposal();
|
||||
|
||||
final PersistableBundle bundle = IkeSaProposalUtils.toPersistableBundle(proposal);
|
||||
final SaProposal resultProposal = IkeSaProposalUtils.fromPersistableBundle(bundle);
|
||||
|
||||
Reference in New Issue
Block a user