Merge changes from topic "ike-params"
* changes: Support converting VcnControlPlaneIkeConfig to/from PersistableBundle Support converting IKE Options to/from PersistableBundle Support converting IkeConfigRequest to/from PersistableBundle Support converting IkeAuthEapConfig to/from PersistableBundle Support converting IkeAuthDigitalSignConfig to/from PersistableBundle Support converting IkeAuthConfig to/from PersistableBundle Support converting IkeSessionParams to/from PersistableBundle
This commit is contained in:
@@ -19,11 +19,13 @@ 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.net.vcn.persistablebundleutils.IkeSessionParamsUtils;
|
||||
import android.net.vcn.persistablebundleutils.TunnelModeChildSessionParamsUtils;
|
||||
import android.os.PersistableBundle;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@@ -38,14 +40,11 @@ import java.util.Objects;
|
||||
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;
|
||||
@NonNull private final IkeSessionParams mIkeParams;
|
||||
|
||||
private static final String CHILD_PARAMS_KEY = "mChildParams";
|
||||
@Nullable private final TunnelModeChildSessionParams mChildParams;
|
||||
@NonNull private final TunnelModeChildSessionParams mChildParams;
|
||||
|
||||
private static final ArraySet<String> BUNDLE_KEY_SET = new ArraySet<>();
|
||||
|
||||
@@ -80,11 +79,19 @@ public final class VcnControlPlaneIkeConfig extends VcnControlPlaneConfig {
|
||||
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.
|
||||
Objects.requireNonNull(ikeParamsBundle, "IKE Session Params was null");
|
||||
Objects.requireNonNull(childParamsBundle, "Child Session Params was null");
|
||||
|
||||
mIkeParams = null;
|
||||
mChildParams = null;
|
||||
mIkeParams = IkeSessionParamsUtils.fromPersistableBundle(ikeParamsBundle);
|
||||
mChildParams = TunnelModeChildSessionParamsUtils.fromPersistableBundle(childParamsBundle);
|
||||
|
||||
for (String key : in.keySet()) {
|
||||
if (!BUNDLE_KEY_SET.contains(key)) {
|
||||
Log.w(TAG, "Found an unexpected key in the PersistableBundle: " + key);
|
||||
}
|
||||
}
|
||||
|
||||
validate();
|
||||
}
|
||||
|
||||
private void validate() {
|
||||
@@ -101,9 +108,11 @@ public final class VcnControlPlaneIkeConfig extends VcnControlPlaneConfig {
|
||||
@NonNull
|
||||
public PersistableBundle toPersistableBundle() {
|
||||
final PersistableBundle result = super.toPersistableBundle();
|
||||
|
||||
// STOPSHIP: b/163604823 Support converting mIkeParams and mChildParams to
|
||||
// PersistableBundles.
|
||||
result.putPersistableBundle(
|
||||
IKE_PARAMS_KEY, IkeSessionParamsUtils.toPersistableBundle(mIkeParams));
|
||||
result.putPersistableBundle(
|
||||
CHILD_PARAMS_KEY,
|
||||
TunnelModeChildSessionParamsUtils.toPersistableBundle(mChildParams));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -134,10 +143,9 @@ public final class VcnControlPlaneIkeConfig extends VcnControlPlaneConfig {
|
||||
|
||||
VcnControlPlaneIkeConfig other = (VcnControlPlaneIkeConfig) o;
|
||||
|
||||
// STOPSHIP: b/163604823 Also check mIkeParams and mChildParams when it is supported to
|
||||
// construct mIkeParams and mChildParams from PersistableBundles. They are not checked
|
||||
// now so that VcnGatewayConnectionConfigTest and VcnConfigTest can pass.
|
||||
return super.equals(o);
|
||||
return super.equals(o)
|
||||
&& Objects.equals(mIkeParams, other.mIkeParams)
|
||||
&& Objects.equals(mChildParams, other.mChildParams);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
|
||||
@@ -18,18 +18,24 @@ package android.net.vcn.persistablebundleutils;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* CertUtils provides utility methods for constructing Certificate.
|
||||
* CertUtils provides utility methods for constructing Certificate and PrivateKey.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class CertUtils {
|
||||
private static final String CERT_TYPE_X509 = "X.509";
|
||||
private static final String PRIVATE_KEY_TYPE_RSA = "RSA";
|
||||
|
||||
/** Decodes an ASN.1 DER encoded Certificate */
|
||||
public static X509Certificate certificateFromByteArray(byte[] derEncoded) {
|
||||
@@ -43,4 +49,18 @@ public class CertUtils {
|
||||
throw new IllegalArgumentException("Fail to decode certificate", e);
|
||||
}
|
||||
}
|
||||
|
||||
/** Decodes a PKCS#8 encoded RSA private key */
|
||||
public static RSAPrivateKey privateKeyFromByteArray(byte[] pkcs8Encoded) {
|
||||
Objects.requireNonNull(pkcs8Encoded, "pkcs8Encoded was null");
|
||||
PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(pkcs8Encoded);
|
||||
|
||||
try {
|
||||
KeyFactory keyFactory = KeyFactory.getInstance(PRIVATE_KEY_TYPE_RSA);
|
||||
|
||||
return (RSAPrivateKey) keyFactory.generatePrivate(privateKeySpec);
|
||||
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
|
||||
throw new IllegalArgumentException("Fail to decode PrivateKey", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,513 @@
|
||||
/*
|
||||
* 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 android.system.OsConstants.AF_INET;
|
||||
import static android.system.OsConstants.AF_INET6;
|
||||
|
||||
import static com.android.internal.annotations.VisibleForTesting.Visibility;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.net.InetAddresses;
|
||||
import android.net.eap.EapSessionConfig;
|
||||
import android.net.ipsec.ike.IkeSaProposal;
|
||||
import android.net.ipsec.ike.IkeSessionParams;
|
||||
import android.net.ipsec.ike.IkeSessionParams.ConfigRequestIpv4PcscfServer;
|
||||
import android.net.ipsec.ike.IkeSessionParams.ConfigRequestIpv6PcscfServer;
|
||||
import android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig;
|
||||
import android.net.ipsec.ike.IkeSessionParams.IkeAuthDigitalSignLocalConfig;
|
||||
import android.net.ipsec.ike.IkeSessionParams.IkeAuthDigitalSignRemoteConfig;
|
||||
import android.net.ipsec.ike.IkeSessionParams.IkeAuthEapConfig;
|
||||
import android.net.ipsec.ike.IkeSessionParams.IkeAuthPskConfig;
|
||||
import android.net.ipsec.ike.IkeSessionParams.IkeConfigRequest;
|
||||
import android.os.PersistableBundle;
|
||||
import android.util.ArraySet;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.server.vcn.util.PersistableBundleUtils;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.cert.CertificateEncodingException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Abstract utility class to convert IkeSessionParams to/from PersistableBundle.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||
public final class IkeSessionParamsUtils {
|
||||
private static final String SERVER_HOST_NAME_KEY = "SERVER_HOST_NAME_KEY";
|
||||
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 CONFIG_REQUESTS_KEY = "CONFIG_REQUESTS_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";
|
||||
private static final String DPD_DELAY_SEC_KEY = "DPD_DELAY_SEC_KEY";
|
||||
private static final String NATT_KEEPALIVE_DELAY_SEC_KEY = "NATT_KEEPALIVE_DELAY_SEC_KEY";
|
||||
private static final String IKE_OPTIONS_KEY = "IKE_OPTIONS_KEY";
|
||||
|
||||
private static final Set<Integer> IKE_OPTIONS = new ArraySet<>();
|
||||
|
||||
static {
|
||||
IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_ACCEPT_ANY_REMOTE_ID);
|
||||
IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_EAP_ONLY_AUTH);
|
||||
IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_MOBIKE);
|
||||
}
|
||||
|
||||
/** Serializes an IkeSessionParams to a PersistableBundle. */
|
||||
@NonNull
|
||||
public static PersistableBundle toPersistableBundle(@NonNull IkeSessionParams params) {
|
||||
if (params.getConfiguredNetwork() != null || params.getIke3gppExtension() != null) {
|
||||
throw new IllegalStateException(
|
||||
"Cannot convert a IkeSessionParams with a caller configured network or with"
|
||||
+ " 3GPP extension enabled");
|
||||
}
|
||||
|
||||
final PersistableBundle result = new PersistableBundle();
|
||||
|
||||
result.putString(SERVER_HOST_NAME_KEY, params.getServerHostname());
|
||||
|
||||
final PersistableBundle saProposalBundle =
|
||||
PersistableBundleUtils.fromList(
|
||||
params.getSaProposals(), IkeSaProposalUtils::toPersistableBundle);
|
||||
result.putPersistableBundle(SA_PROPOSALS_KEY, saProposalBundle);
|
||||
|
||||
result.putPersistableBundle(
|
||||
LOCAL_ID_KEY,
|
||||
IkeIdentificationUtils.toPersistableBundle(params.getLocalIdentification()));
|
||||
result.putPersistableBundle(
|
||||
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()));
|
||||
|
||||
final List<ConfigRequest> reqList = new ArrayList<>();
|
||||
for (IkeConfigRequest req : params.getConfigurationRequests()) {
|
||||
reqList.add(new ConfigRequest(req));
|
||||
}
|
||||
final PersistableBundle configReqListBundle =
|
||||
PersistableBundleUtils.fromList(reqList, ConfigRequest::toPersistableBundle);
|
||||
result.putPersistableBundle(CONFIG_REQUESTS_KEY, configReqListBundle);
|
||||
|
||||
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());
|
||||
|
||||
final List<Integer> enabledIkeOptions = new ArrayList<>();
|
||||
for (int option : IKE_OPTIONS) {
|
||||
if (params.hasIkeOption(option)) {
|
||||
enabledIkeOptions.add(option);
|
||||
}
|
||||
}
|
||||
|
||||
final int[] optionArray = enabledIkeOptions.stream().mapToInt(i -> i).toArray();
|
||||
result.putIntArray(IKE_OPTIONS_KEY, optionArray);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Constructs an IkeSessionParams by deserializing a PersistableBundle. */
|
||||
@NonNull
|
||||
public static IkeSessionParams fromPersistableBundle(@NonNull PersistableBundle in) {
|
||||
Objects.requireNonNull(in, "PersistableBundle is null");
|
||||
|
||||
final IkeSessionParams.Builder builder = new IkeSessionParams.Builder();
|
||||
|
||||
builder.setServerHostname(in.getString(SERVER_HOST_NAME_KEY));
|
||||
|
||||
PersistableBundle proposalBundle = in.getPersistableBundle(SA_PROPOSALS_KEY);
|
||||
Objects.requireNonNull(in, "SA Proposals was null");
|
||||
List<IkeSaProposal> saProposals =
|
||||
PersistableBundleUtils.toList(
|
||||
proposalBundle, IkeSaProposalUtils::fromPersistableBundle);
|
||||
for (IkeSaProposal proposal : saProposals) {
|
||||
builder.addSaProposal(proposal);
|
||||
}
|
||||
|
||||
builder.setLocalIdentification(
|
||||
IkeIdentificationUtils.fromPersistableBundle(
|
||||
in.getPersistableBundle(LOCAL_ID_KEY)));
|
||||
builder.setRemoteIdentification(
|
||||
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));
|
||||
|
||||
final PersistableBundle configReqListBundle = in.getPersistableBundle(CONFIG_REQUESTS_KEY);
|
||||
Objects.requireNonNull(configReqListBundle, "Config request list was null");
|
||||
final List<ConfigRequest> reqList =
|
||||
PersistableBundleUtils.toList(configReqListBundle, ConfigRequest::new);
|
||||
for (ConfigRequest req : reqList) {
|
||||
switch (req.type) {
|
||||
case ConfigRequest.IPV4_P_CSCF_ADDRESS:
|
||||
if (req.address == null) {
|
||||
builder.addPcscfServerRequest(AF_INET);
|
||||
} else {
|
||||
builder.addPcscfServerRequest(req.address);
|
||||
}
|
||||
break;
|
||||
case ConfigRequest.IPV6_P_CSCF_ADDRESS:
|
||||
if (req.address == null) {
|
||||
builder.addPcscfServerRequest(AF_INET6);
|
||||
} else {
|
||||
builder.addPcscfServerRequest(req.address);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException(
|
||||
"Unrecognized config request type: " + req.type);
|
||||
}
|
||||
}
|
||||
|
||||
// Clear IKE Options that are by default enabled
|
||||
for (int option : IKE_OPTIONS) {
|
||||
builder.removeIkeOption(option);
|
||||
}
|
||||
|
||||
final int[] optionArray = in.getIntArray(IKE_OPTIONS_KEY);
|
||||
for (int option : optionArray) {
|
||||
builder.addIkeOption(option);
|
||||
}
|
||||
|
||||
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 if (authConfig instanceof IkeAuthDigitalSignLocalConfig) {
|
||||
IkeAuthDigitalSignLocalConfig config = (IkeAuthDigitalSignLocalConfig) authConfig;
|
||||
return IkeAuthDigitalSignConfigUtils.toPersistableBundle(
|
||||
config, createPersistableBundle(IKE_AUTH_METHOD_PUB_KEY_SIGNATURE));
|
||||
} else if (authConfig instanceof IkeAuthDigitalSignRemoteConfig) {
|
||||
IkeAuthDigitalSignRemoteConfig config = (IkeAuthDigitalSignRemoteConfig) authConfig;
|
||||
return IkeAuthDigitalSignConfigUtils.toPersistableBundle(
|
||||
config, createPersistableBundle(IKE_AUTH_METHOD_PUB_KEY_SIGNATURE));
|
||||
} else if (authConfig instanceof IkeAuthEapConfig) {
|
||||
IkeAuthEapConfig config = (IkeAuthEapConfig) authConfig;
|
||||
return IkeAuthEapConfigUtils.toPersistableBundle(
|
||||
config, createPersistableBundle(IKE_AUTH_METHOD_EAP));
|
||||
} else {
|
||||
throw new IllegalStateException("Invalid IkeAuthConfig subclass");
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
return;
|
||||
case IKE_AUTH_METHOD_PUB_KEY_SIGNATURE:
|
||||
if (remoteMethodType != IKE_AUTH_METHOD_PUB_KEY_SIGNATURE) {
|
||||
throw new IllegalArgumentException(
|
||||
"Expect remote auth method to be digital signature based, but was "
|
||||
+ remoteMethodType);
|
||||
}
|
||||
IkeAuthDigitalSignConfigUtils.setBuilderByReadingPersistableBundle(
|
||||
localAuthBundle, remoteAuthBundle, builder);
|
||||
return;
|
||||
case IKE_AUTH_METHOD_EAP:
|
||||
if (remoteMethodType != IKE_AUTH_METHOD_PUB_KEY_SIGNATURE) {
|
||||
throw new IllegalArgumentException(
|
||||
"When using EAP for local authentication, expect remote auth"
|
||||
+ " method to be digital signature based, but was "
|
||||
+ remoteMethodType);
|
||||
}
|
||||
IkeAuthEapConfigUtils.setBuilderByReadingPersistableBundle(
|
||||
localAuthBundle, remoteAuthBundle, builder);
|
||||
return;
|
||||
default:
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid EAP method type " + localMethodType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
private static class IkeAuthDigitalSignConfigUtils {
|
||||
private static final String END_CERT_KEY = "END_CERT_KEY";
|
||||
private static final String INTERMEDIATE_CERTS_KEY = "INTERMEDIATE_CERTS_KEY";
|
||||
private static final String PRIVATE_KEY_KEY = "PRIVATE_KEY_KEY";
|
||||
private static final String TRUST_CERT_KEY = "TRUST_CERT_KEY";
|
||||
|
||||
@NonNull
|
||||
public static PersistableBundle toPersistableBundle(
|
||||
@NonNull IkeAuthDigitalSignLocalConfig config, @NonNull PersistableBundle result) {
|
||||
try {
|
||||
result.putPersistableBundle(
|
||||
END_CERT_KEY,
|
||||
PersistableBundleUtils.fromByteArray(
|
||||
config.getClientEndCertificate().getEncoded()));
|
||||
|
||||
final List<X509Certificate> certList = config.getIntermediateCertificates();
|
||||
final List<byte[]> encodedCertList = new ArrayList<>(certList.size());
|
||||
for (X509Certificate cert : certList) {
|
||||
encodedCertList.add(cert.getEncoded());
|
||||
}
|
||||
|
||||
final PersistableBundle certsBundle =
|
||||
PersistableBundleUtils.fromList(
|
||||
encodedCertList, PersistableBundleUtils::fromByteArray);
|
||||
result.putPersistableBundle(INTERMEDIATE_CERTS_KEY, certsBundle);
|
||||
} catch (CertificateEncodingException e) {
|
||||
throw new IllegalArgumentException("Fail to encode certificate");
|
||||
}
|
||||
|
||||
// TODO: b/170670506 Consider putting PrivateKey in Android KeyStore
|
||||
result.putPersistableBundle(
|
||||
PRIVATE_KEY_KEY,
|
||||
PersistableBundleUtils.fromByteArray(config.getPrivateKey().getEncoded()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static PersistableBundle toPersistableBundle(
|
||||
@NonNull IkeAuthDigitalSignRemoteConfig config, @NonNull PersistableBundle result) {
|
||||
try {
|
||||
X509Certificate caCert = config.getRemoteCaCert();
|
||||
if (caCert != null) {
|
||||
result.putPersistableBundle(
|
||||
TRUST_CERT_KEY,
|
||||
PersistableBundleUtils.fromByteArray(caCert.getEncoded()));
|
||||
}
|
||||
} catch (CertificateEncodingException e) {
|
||||
throw new IllegalArgumentException("Fail to encode the certificate");
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
// Deserialize localAuth
|
||||
final PersistableBundle endCertBundle =
|
||||
localAuthBundle.getPersistableBundle(END_CERT_KEY);
|
||||
Objects.requireNonNull(endCertBundle, "End cert was null");
|
||||
final byte[] encodedCert = PersistableBundleUtils.toByteArray(endCertBundle);
|
||||
final X509Certificate endCert = CertUtils.certificateFromByteArray(encodedCert);
|
||||
|
||||
final PersistableBundle certsBundle =
|
||||
localAuthBundle.getPersistableBundle(INTERMEDIATE_CERTS_KEY);
|
||||
Objects.requireNonNull(certsBundle, "Intermediate certs was null");
|
||||
final List<byte[]> encodedCertList =
|
||||
PersistableBundleUtils.toList(certsBundle, PersistableBundleUtils::toByteArray);
|
||||
final List<X509Certificate> certList = new ArrayList<>(encodedCertList.size());
|
||||
for (byte[] encoded : encodedCertList) {
|
||||
certList.add(CertUtils.certificateFromByteArray(encoded));
|
||||
}
|
||||
|
||||
final PersistableBundle privateKeyBundle =
|
||||
localAuthBundle.getPersistableBundle(PRIVATE_KEY_KEY);
|
||||
Objects.requireNonNull(privateKeyBundle, "PrivateKey bundle was null");
|
||||
final PrivateKey privateKey =
|
||||
CertUtils.privateKeyFromByteArray(
|
||||
PersistableBundleUtils.toByteArray(privateKeyBundle));
|
||||
|
||||
// Deserialize remoteAuth
|
||||
final PersistableBundle trustCertBundle =
|
||||
remoteAuthBundle.getPersistableBundle(TRUST_CERT_KEY);
|
||||
|
||||
X509Certificate caCert = null;
|
||||
if (trustCertBundle != null) {
|
||||
final byte[] encodedCaCert = PersistableBundleUtils.toByteArray(trustCertBundle);
|
||||
caCert = CertUtils.certificateFromByteArray(encodedCaCert);
|
||||
}
|
||||
|
||||
builder.setAuthDigitalSignature(caCert, endCert, certList, privateKey);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class IkeAuthEapConfigUtils {
|
||||
private static final String EAP_CONFIG_KEY = "EAP_CONFIG_KEY";
|
||||
|
||||
@NonNull
|
||||
public static PersistableBundle toPersistableBundle(
|
||||
@NonNull IkeAuthEapConfig config, @NonNull PersistableBundle result) {
|
||||
result.putPersistableBundle(
|
||||
EAP_CONFIG_KEY,
|
||||
EapSessionConfigUtils.toPersistableBundle(config.getEapConfig()));
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void setBuilderByReadingPersistableBundle(
|
||||
@NonNull PersistableBundle localAuthBundle,
|
||||
@NonNull PersistableBundle remoteAuthBundle,
|
||||
@NonNull IkeSessionParams.Builder builder) {
|
||||
// Deserialize localAuth
|
||||
final PersistableBundle eapBundle =
|
||||
localAuthBundle.getPersistableBundle(EAP_CONFIG_KEY);
|
||||
Objects.requireNonNull(eapBundle, "EAP Config was null");
|
||||
final EapSessionConfig eapConfig =
|
||||
EapSessionConfigUtils.fromPersistableBundle(eapBundle);
|
||||
|
||||
// Deserialize remoteAuth
|
||||
final PersistableBundle trustCertBundle =
|
||||
remoteAuthBundle.getPersistableBundle(
|
||||
IkeAuthDigitalSignConfigUtils.TRUST_CERT_KEY);
|
||||
|
||||
X509Certificate serverCaCert = null;
|
||||
if (trustCertBundle != null) {
|
||||
final byte[] encodedCaCert = PersistableBundleUtils.toByteArray(trustCertBundle);
|
||||
serverCaCert = CertUtils.certificateFromByteArray(encodedCaCert);
|
||||
}
|
||||
builder.setAuthEap(serverCaCert, eapConfig);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class ConfigRequest {
|
||||
private static final int IPV4_P_CSCF_ADDRESS = 1;
|
||||
private static final int IPV6_P_CSCF_ADDRESS = 2;
|
||||
|
||||
private static final String TYPE_KEY = "type";
|
||||
private static final String ADDRESS_KEY = "address";
|
||||
|
||||
public final int type;
|
||||
|
||||
// Null when it is an empty request
|
||||
@Nullable public final InetAddress address;
|
||||
|
||||
ConfigRequest(IkeConfigRequest config) {
|
||||
if (config instanceof ConfigRequestIpv4PcscfServer) {
|
||||
type = IPV4_P_CSCF_ADDRESS;
|
||||
address = ((ConfigRequestIpv4PcscfServer) config).getAddress();
|
||||
} else if (config instanceof ConfigRequestIpv6PcscfServer) {
|
||||
type = IPV6_P_CSCF_ADDRESS;
|
||||
address = ((ConfigRequestIpv6PcscfServer) config).getAddress();
|
||||
} else {
|
||||
throw new IllegalStateException("Unknown TunnelModeChildConfigRequest");
|
||||
}
|
||||
}
|
||||
|
||||
ConfigRequest(PersistableBundle in) {
|
||||
Objects.requireNonNull(in, "PersistableBundle was null");
|
||||
|
||||
type = in.getInt(TYPE_KEY);
|
||||
|
||||
String addressStr = in.getString(ADDRESS_KEY);
|
||||
if (addressStr == null) {
|
||||
address = null;
|
||||
} else {
|
||||
address = InetAddresses.parseNumericAddress(addressStr);
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public PersistableBundle toPersistableBundle() {
|
||||
final PersistableBundle result = new PersistableBundle();
|
||||
|
||||
result.putInt(TYPE_KEY, type);
|
||||
if (address != null) {
|
||||
result.putString(ADDRESS_KEY, address.getHostAddress());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
21
tests/vcn/assets/client-end-cert.pem
Normal file
21
tests/vcn/assets/client-end-cert.pem
Normal file
@@ -0,0 +1,21 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDaDCCAlCgAwIBAgIIcorRI3n29E4wDQYJKoZIhvcNAQELBQAwQTELMAkGA1UE
|
||||
BhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxIDAeBgNVBAMTF3R3by5jYS50ZXN0LmFu
|
||||
ZHJvaWQubmV0MB4XDTIwMDQxNDA1MDM0OVoXDTIzMDQxNDA1MDM0OVowRTELMAkG
|
||||
A1UEBhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxJDAiBgNVBAMTG2NsaWVudC50ZXN0
|
||||
LmlrZS5hbmRyb2lkLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
|
||||
AK/cK+sIaiQlJYvy5+Dq70sJbgR7PO1uS2qkLRP7Wb3z5SNvz94nQvZRrFn1AFIE
|
||||
CpfESh5kUF6gJe7t7NR3mpQ98iEosCRBMDJT8qB+EeHiL4wkrmCE9sYMTyvaApRc
|
||||
6Qzozn/9kKma7Qpj/25AvoPluTERqhZ6AQ77BJeb6FNOAoO1Aoe9GJuB1xmRxjRw
|
||||
D0mwusL+ciQ/7uKlsFP5VO5XqACcohXSerzO8jcD9necBvka3SDepqqzn1K0NPRC
|
||||
25fMmS5kSjddKtKOif7w2NI3OpVsmP3kHv66If73VURsy0lgXPYyKkq8lAMrtmXG
|
||||
R7svFGPbEl+Swkpr3b+dzF8CAwEAAaNgMF4wHwYDVR0jBBgwFoAUcqSu1uRYT/DL
|
||||
bLoDNUz38nGvCKQwJgYDVR0RBB8wHYIbY2xpZW50LnRlc3QuaWtlLmFuZHJvaWQu
|
||||
bmV0MBMGA1UdJQQMMAoGCCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUAA4IBAQCa53tK
|
||||
I9RM9/MutZ5KNG2Gfs2cqaPyv8ZRhs90HDWZhkFVu7prywJAxOd2hxxHPsvgurio
|
||||
4bKAxnT4EXevgz5YoCbj2TPIL9TdFYh59zZ97XXMxk+SRdypgF70M6ETqKPs3hDP
|
||||
ZRMMoHvvYaqaPvp4StSBX9A44gSyjHxVYJkrjDZ0uffKg5lFL5IPvqfdmSRSpGab
|
||||
SyGTP4OLTy0QiNV3pBsJGdl0h5BzuTPR9OTl4xgeqqBQy2bDjmfJBuiYyCSCkPi7
|
||||
T3ohDYCymhuSkuktHPNG1aKllUJaw0tuZuNydlgdAveXPYfM36uvK0sfd9qr9pAy
|
||||
rmkYV2MAWguFeckh
|
||||
-----END CERTIFICATE-----
|
||||
28
tests/vcn/assets/client-private-key.key
Normal file
28
tests/vcn/assets/client-private-key.key
Normal file
@@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCv3CvrCGokJSWL
|
||||
8ufg6u9LCW4EezztbktqpC0T+1m98+Ujb8/eJ0L2UaxZ9QBSBAqXxEoeZFBeoCXu
|
||||
7ezUd5qUPfIhKLAkQTAyU/KgfhHh4i+MJK5ghPbGDE8r2gKUXOkM6M5//ZCpmu0K
|
||||
Y/9uQL6D5bkxEaoWegEO+wSXm+hTTgKDtQKHvRibgdcZkcY0cA9JsLrC/nIkP+7i
|
||||
pbBT+VTuV6gAnKIV0nq8zvI3A/Z3nAb5Gt0g3qaqs59StDT0QtuXzJkuZEo3XSrS
|
||||
jon+8NjSNzqVbJj95B7+uiH+91VEbMtJYFz2MipKvJQDK7Zlxke7LxRj2xJfksJK
|
||||
a92/ncxfAgMBAAECggEAQztaMvW5lm35J8LKsWs/5qEJRX9T8LWs8W0oqq36Riub
|
||||
G2wgvR6ndAIPcSjAYZqX7iOl7m6NZ0+0kN63HxdGqovwKIskpAekBGmhpYftED1n
|
||||
zh0r6UyMB3UnQ22KdOv8UOokIDxxdNX8728BdUYdT9Ggdkj5jLRB+VcwD0IUlNvo
|
||||
zzTpURV9HEd87uiLqd4AAHXSI0lIHI5U43z24HI/J6/YbYHT3Rlh6CIa/LuwO6vL
|
||||
gFkgqg0/oy6yJtjrHtzNVA67F0UaH62hR4YFgbC0d955SJnDidWOv/0j2DMpfdCc
|
||||
9kFAcPwUSyykvUSLnGIKWSG4D+6gzIeAeUx4oO7kMQKBgQDVNRkX8AGTHyLg+NXf
|
||||
spUWWcodwVioXl30Q7h6+4bt8OI61UbhQ7wX61wvJ1cySpa2KOYa2UdagQVhGhhL
|
||||
ADu363R77uXF/jZgzVfmjjyJ2nfDqRgHWRTlSkuq/jCOQCz7VIPHRZg5WL/9D4ms
|
||||
TAqMjpzqeMfFZI+w4/+xpcJIuQKBgQDTKBy+ZuerWrVT9icWKvLU58o5EVj/2yFy
|
||||
GJvKm+wRAAX2WzjNnR4HVd4DmMREVz1BPYby0j5gqjvtDsxYYu39+NT7JvMioLLK
|
||||
QPj+7k5geYgNqVgCxB1vP89RhY2X1RLrN9sTXOodgFPeXOQWNYITkGp3eQpx4nTJ
|
||||
+K/al3oB1wKBgAjnc8nVIyuyxDEjE0OJYMKTM2a0uXAmqMPXxC+Wq5bqVXhhidlE
|
||||
i+lv0eTCPtkB1nN7F8kNQ/aaps/cWCFhvBy9P5shagUvzbOTP9WIIS0cq53HRRKh
|
||||
fMbqqGhWv05hjb9dUzeSR341n6cA7B3++v3Nwu3j52vt/DZF/1q68nc5AoGAS0SU
|
||||
ImbKE/GsizZGLoe2sZ/CHN+LKwCwhlwxRGKaHmE0vuE7eUeVSaYZEo0lAPtb8WJ+
|
||||
NRYueASWgeTxgFwbW5mUScZTirdfo+rPFwhZVdhcYApKPgosN9i2DOgfVcz1BnWN
|
||||
mPRY25U/0BaqkyQVruWeneG+kGPZn5kPDktKiVcCgYEAkzwU9vCGhm7ZVALvx/zR
|
||||
wARz2zsL9ImBc0P4DK1ld8g90FEnHrEgeI9JEwz0zFHOCMLwlk7kG0Xev7vfjZ7G
|
||||
xSqtQYOH33Qp6rtBOgdt8hSyDFvakvDl6bqhAw52gelO3MTpAB1+ZsfZ5gFx13Jf
|
||||
idNFcaIrC52PtZIH7QCzdDY=
|
||||
-----END PRIVATE KEY-----
|
||||
@@ -98,6 +98,13 @@ public class VcnControlPlaneIkeConfigTest {
|
||||
assertEquals(CHILD_PARAMS, config.getChildSessionParams());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPersistableBundle() {
|
||||
final VcnControlPlaneIkeConfig config = buildTestConfig();
|
||||
|
||||
assertEquals(config, new VcnControlPlaneIkeConfig(config.toPersistableBundle()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructConfigWithoutIkeParams() {
|
||||
try {
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* 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 android.system.OsConstants.AF_INET;
|
||||
import static android.system.OsConstants.AF_INET6;
|
||||
import static android.telephony.TelephonyManager.APPTYPE_USIM;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import android.net.InetAddresses;
|
||||
import android.net.eap.EapSessionConfig;
|
||||
import android.net.ipsec.ike.IkeFqdnIdentification;
|
||||
import android.net.ipsec.ike.IkeSessionParams;
|
||||
import android.os.PersistableBundle;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.internal.org.bouncycastle.util.io.pem.PemObject;
|
||||
import com.android.internal.org.bouncycastle.util.io.pem.PemReader;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
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 testEncodeRecodeParamsWithConfigRequests() throws Exception {
|
||||
final Inet4Address ipv4Address =
|
||||
(Inet4Address) InetAddresses.parseNumericAddress("192.0.2.100");
|
||||
final Inet6Address ipv6Address =
|
||||
(Inet6Address) InetAddresses.parseNumericAddress("2001:db8::1");
|
||||
|
||||
final IkeSessionParams params =
|
||||
createBuilderMinimum()
|
||||
.addPcscfServerRequest(AF_INET)
|
||||
.addPcscfServerRequest(AF_INET6)
|
||||
.addPcscfServerRequest(ipv4Address)
|
||||
.addPcscfServerRequest(ipv6Address)
|
||||
.build();
|
||||
verifyPersistableBundleEncodeDecodeIsLossless(params);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeRecodeParamsWithAuthPsk() throws Exception {
|
||||
final IkeSessionParams params = createBuilderMinimum().setAuthPsk("psk".getBytes()).build();
|
||||
verifyPersistableBundleEncodeDecodeIsLossless(params);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeRecodeParamsWithIkeOptions() throws Exception {
|
||||
final IkeSessionParams params =
|
||||
createBuilderMinimum()
|
||||
.addIkeOption(IkeSessionParams.IKE_OPTION_ACCEPT_ANY_REMOTE_ID)
|
||||
.addIkeOption(IkeSessionParams.IKE_OPTION_MOBIKE)
|
||||
.build();
|
||||
verifyPersistableBundleEncodeDecodeIsLossless(params);
|
||||
}
|
||||
|
||||
private static InputStream openAssetsFile(String fileName) throws Exception {
|
||||
return InstrumentationRegistry.getContext().getResources().getAssets().open(fileName);
|
||||
}
|
||||
|
||||
private static X509Certificate createCertFromPemFile(String fileName) throws Exception {
|
||||
final CertificateFactory factory = CertificateFactory.getInstance("X.509");
|
||||
return (X509Certificate) factory.generateCertificate(openAssetsFile(fileName));
|
||||
}
|
||||
|
||||
private static RSAPrivateKey createRsaPrivateKeyFromKeyFile(String fileName) throws Exception {
|
||||
final PemObject pemObject =
|
||||
new PemReader(new InputStreamReader(openAssetsFile(fileName))).readPemObject();
|
||||
return (RSAPrivateKey) CertUtils.privateKeyFromByteArray(pemObject.getContent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeRecodeParamsWithDigitalSignAuth() throws Exception {
|
||||
final X509Certificate serverCaCert = createCertFromPemFile("self-signed-ca.pem");
|
||||
final X509Certificate clientEndCert = createCertFromPemFile("client-end-cert.pem");
|
||||
final RSAPrivateKey clientPrivateKey =
|
||||
createRsaPrivateKeyFromKeyFile("client-private-key.key");
|
||||
|
||||
final IkeSessionParams params =
|
||||
createBuilderMinimum()
|
||||
.setAuthDigitalSignature(serverCaCert, clientEndCert, clientPrivateKey)
|
||||
.build();
|
||||
verifyPersistableBundleEncodeDecodeIsLossless(params);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeRecodeParamsWithEapAuth() throws Exception {
|
||||
final X509Certificate serverCaCert = createCertFromPemFile("self-signed-ca.pem");
|
||||
|
||||
final byte[] eapId = "test@android.net".getBytes(StandardCharsets.US_ASCII);
|
||||
final int subId = 1;
|
||||
final EapSessionConfig eapConfig =
|
||||
new EapSessionConfig.Builder()
|
||||
.setEapIdentity(eapId)
|
||||
.setEapSimConfig(subId, APPTYPE_USIM)
|
||||
.setEapAkaConfig(subId, APPTYPE_USIM)
|
||||
.build();
|
||||
|
||||
final IkeSessionParams params =
|
||||
createBuilderMinimum().setAuthEap(serverCaCert, eapConfig).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