Merge "Ignore other IKE options if IkeTunnelConnectionParams is set" am: 48160f9b9b

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1978249

Change-Id: I3595e032cff0b18959150139d9f84cb817784fb2
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Chiachang Wang
2022-04-07 10:38:03 +00:00
committed by Automerger Merge Worker
2 changed files with 185 additions and 162 deletions

View File

@@ -25,12 +25,6 @@ import static android.net.IpSecAlgorithm.AUTH_HMAC_SHA384;
import static android.net.IpSecAlgorithm.AUTH_HMAC_SHA512; import static android.net.IpSecAlgorithm.AUTH_HMAC_SHA512;
import static android.net.IpSecAlgorithm.CRYPT_AES_CBC; import static android.net.IpSecAlgorithm.CRYPT_AES_CBC;
import static android.net.IpSecAlgorithm.CRYPT_AES_CTR; import static android.net.IpSecAlgorithm.CRYPT_AES_CTR;
import static android.net.eap.EapSessionConfig.EapMsChapV2Config;
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 com.android.internal.annotations.VisibleForTesting.Visibility; import static com.android.internal.annotations.VisibleForTesting.Visibility;
import static com.android.internal.util.Preconditions.checkStringNotEmpty; import static com.android.internal.util.Preconditions.checkStringNotEmpty;
@@ -40,6 +34,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.annotation.RequiresFeature; import android.annotation.RequiresFeature;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.net.ipsec.ike.IkeDerAsn1DnIdentification;
import android.net.ipsec.ike.IkeFqdnIdentification; import android.net.ipsec.ike.IkeFqdnIdentification;
import android.net.ipsec.ike.IkeIdentification; import android.net.ipsec.ike.IkeIdentification;
import android.net.ipsec.ike.IkeIpv4AddrIdentification; import android.net.ipsec.ike.IkeIpv4AddrIdentification;
@@ -119,8 +114,8 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
DEFAULT_ALGORITHMS = Collections.unmodifiableList(algorithms); DEFAULT_ALGORITHMS = Collections.unmodifiableList(algorithms);
} }
@NonNull private final String mServerAddr; @Nullable private final String mServerAddr;
@NonNull private final String mUserIdentity; @Nullable private final String mUserIdentity;
// PSK authentication // PSK authentication
@Nullable private final byte[] mPresharedKey; @Nullable private final byte[] mPresharedKey;
@@ -146,8 +141,8 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
private Ikev2VpnProfile( private Ikev2VpnProfile(
int type, int type,
@NonNull String serverAddr, @Nullable String serverAddr,
@NonNull String userIdentity, @Nullable String userIdentity,
@Nullable byte[] presharedKey, @Nullable byte[] presharedKey,
@Nullable X509Certificate serverRootCaCert, @Nullable X509Certificate serverRootCaCert,
@Nullable String username, @Nullable String username,
@@ -165,8 +160,6 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
@Nullable IkeTunnelConnectionParams ikeTunConnParams) { @Nullable IkeTunnelConnectionParams ikeTunConnParams) {
super(type, excludeLocalRoutes, requiresInternetValidation); super(type, excludeLocalRoutes, requiresInternetValidation);
checkNotNull(serverAddr, MISSING_PARAM_MSG_TMPL, "Server address");
checkNotNull(userIdentity, MISSING_PARAM_MSG_TMPL, "User Identity");
checkNotNull(allowedAlgorithms, MISSING_PARAM_MSG_TMPL, "Allowed Algorithms"); checkNotNull(allowedAlgorithms, MISSING_PARAM_MSG_TMPL, "Allowed Algorithms");
mServerAddr = serverAddr; mServerAddr = serverAddr;
@@ -191,18 +184,12 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
mIsMetered = isMetered; mIsMetered = isMetered;
mMaxMtu = maxMtu; mMaxMtu = maxMtu;
mIsRestrictedToTestNetworks = restrictToTestNetworks; mIsRestrictedToTestNetworks = restrictToTestNetworks;
mIkeTunConnParams = ikeTunConnParams; mIkeTunConnParams = ikeTunConnParams;
validate(); validate();
} }
private void validate() { private void validate() {
// Server Address not validated except to check an address was provided. This allows for
// dual-stack servers and hostname based addresses.
checkStringNotEmpty(mServerAddr, MISSING_PARAM_MSG_TMPL, "Server Address");
checkStringNotEmpty(mUserIdentity, MISSING_PARAM_MSG_TMPL, "User Identity");
// IPv6 MTU is greater; since profiles may be started by the system on IPv4 and IPv6 // IPv6 MTU is greater; since profiles may be started by the system on IPv4 and IPv6
// networks, the VPN must provide a link fulfilling the stricter of the two conditions // networks, the VPN must provide a link fulfilling the stricter of the two conditions
// (at least that of the IPv6 MTU). // (at least that of the IPv6 MTU).
@@ -210,6 +197,15 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
throw new IllegalArgumentException("Max MTU must be at least" + IPV6_MIN_MTU); throw new IllegalArgumentException("Max MTU must be at least" + IPV6_MIN_MTU);
} }
// Skip validating the other fields if mIkeTunConnParams is set because the required
// information should all come from the mIkeTunConnParams.
if (mIkeTunConnParams != null) return;
// Server Address not validated except to check an address was provided. This allows for
// dual-stack servers and hostname based addresses.
checkStringNotEmpty(mServerAddr, MISSING_PARAM_MSG_TMPL, "Server Address");
checkStringNotEmpty(mUserIdentity, MISSING_PARAM_MSG_TMPL, "User Identity");
switch (mType) { switch (mType) {
case TYPE_IKEV2_IPSEC_USER_PASS: case TYPE_IKEV2_IPSEC_USER_PASS:
checkNotNull(mUsername, MISSING_PARAM_MSG_TMPL, "Username"); checkNotNull(mUsername, MISSING_PARAM_MSG_TMPL, "Username");
@@ -286,22 +282,31 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
/** Retrieves the server address string. */ /** Retrieves the server address string. */
@NonNull @NonNull
public String getServerAddr() { public String getServerAddr() {
return mServerAddr; if (mIkeTunConnParams == null) return mServerAddr;
final IkeSessionParams ikeSessionParams = mIkeTunConnParams.getIkeSessionParams();
return ikeSessionParams.getServerHostname();
} }
/** Retrieves the user identity. */ /** Retrieves the user identity. */
@NonNull @NonNull
public String getUserIdentity() { public String getUserIdentity() {
return mUserIdentity; if (mIkeTunConnParams == null) return mUserIdentity;
final IkeSessionParams ikeSessionParams = mIkeTunConnParams.getIkeSessionParams();
return getUserIdentityFromIkeSession(ikeSessionParams);
} }
/** /**
* Retrieves the pre-shared key. * Retrieves the pre-shared key.
* *
* <p>May be null if the profile is not using Pre-shared key authentication. * <p>May be null if the profile is not using Pre-shared key authentication, or the profile is
* built from an {@link IkeTunnelConnectionParams}.
*/ */
@Nullable @Nullable
public byte[] getPresharedKey() { public byte[] getPresharedKey() {
if (mIkeTunConnParams != null) return null;
return mPresharedKey == null ? null : Arrays.copyOf(mPresharedKey, mPresharedKey.length); return mPresharedKey == null ? null : Arrays.copyOf(mPresharedKey, mPresharedKey.length);
} }
@@ -309,46 +314,62 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
* Retrieves the certificate for the server's root CA. * Retrieves the certificate for the server's root CA.
* *
* <p>May be null if the profile is not using RSA Digital Signature Authentication or * <p>May be null if the profile is not using RSA Digital Signature Authentication or
* Username/Password authentication * Username/Password authentication, or the profile is built from an
* {@link IkeTunnelConnectionParams}.
*/ */
@Nullable @Nullable
public X509Certificate getServerRootCaCert() { public X509Certificate getServerRootCaCert() {
if (mIkeTunConnParams != null) return null;
return mServerRootCaCert; return mServerRootCaCert;
} }
/** /**
* Retrieves the username. * Retrieves the username.
* *
* <p>May be null if the profile is not using Username/Password authentication * <p>May be null if the profile is not using Username/Password authentication, or the profile
* is built from an {@link IkeTunnelConnectionParams}.
*/ */
@Nullable @Nullable
public String getUsername() { public String getUsername() {
if (mIkeTunConnParams != null) return null;
return mUsername; return mUsername;
} }
/** /**
* Retrieves the password. * Retrieves the password.
* *
* <p>May be null if the profile is not using Username/Password authentication * <p>May be null if the profile is not using Username/Password authentication, or the profile
* is built from an {@link IkeTunnelConnectionParams}.
*/ */
@Nullable @Nullable
public String getPassword() { public String getPassword() {
if (mIkeTunConnParams != null) return null;
return mPassword; return mPassword;
} }
/** /**
* Retrieves the RSA private key. * Retrieves the RSA private key.
* *
* <p>May be null if the profile is not using RSA Digital Signature authentication * <p>May be null if the profile is not using RSA Digital Signature authentication, or the
* profile is built from an {@link IkeTunnelConnectionParams}.
*/ */
@Nullable @Nullable
public PrivateKey getRsaPrivateKey() { public PrivateKey getRsaPrivateKey() {
if (mIkeTunConnParams != null) return null;
return mRsaPrivateKey; return mRsaPrivateKey;
} }
/** Retrieves the user certificate, if any was set. */ /** Retrieves the user certificate, if any was set.
*
* <p>May be null if the profile is built from an {@link IkeTunnelConnectionParams}.
*/
@Nullable @Nullable
public X509Certificate getUserCert() { public X509Certificate getUserCert() {
if (mIkeTunConnParams != null) return null;
return mUserCert; return mUserCert;
} }
@@ -358,9 +379,14 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
return mProxyInfo; return mProxyInfo;
} }
/** Returns all the algorithms allowed by this VPN profile. */ /** Returns all the algorithms allowed by this VPN profile.
*
* <p>May be an empty list if the profile is built from an {@link IkeTunnelConnectionParams}.
*/
@NonNull @NonNull
public List<String> getAllowedAlgorithms() { public List<String> getAllowedAlgorithms() {
if (mIkeTunConnParams != null) return new ArrayList<>();
return mAllowedAlgorithms; return mAllowedAlgorithms;
} }
@@ -455,18 +481,25 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
@NonNull @NonNull
public VpnProfile toVpnProfile() throws IOException, GeneralSecurityException { public VpnProfile toVpnProfile() throws IOException, GeneralSecurityException {
final VpnProfile profile = new VpnProfile("" /* Key; value unused by IKEv2VpnProfile(s) */, final VpnProfile profile = new VpnProfile("" /* Key; value unused by IKEv2VpnProfile(s) */,
mIsRestrictedToTestNetworks, mExcludeLocalRoutes, mRequiresInternetValidation); mIsRestrictedToTestNetworks, mExcludeLocalRoutes, mRequiresInternetValidation,
profile.type = mType; mIkeTunConnParams);
profile.server = mServerAddr;
profile.ipsecIdentifier = mUserIdentity; profile.server = getServerAddr();
profile.ipsecIdentifier = getUserIdentity();
profile.proxy = mProxyInfo; profile.proxy = mProxyInfo;
profile.setAllowedAlgorithms(mAllowedAlgorithms);
profile.isBypassable = mIsBypassable; profile.isBypassable = mIsBypassable;
profile.isMetered = mIsMetered; profile.isMetered = mIsMetered;
profile.maxMtu = mMaxMtu; profile.maxMtu = mMaxMtu;
profile.areAuthParamsInline = true; profile.areAuthParamsInline = true;
profile.saveLogin = true; profile.saveLogin = true;
// The other fields should come from mIkeTunConnParams if it's available.
if (mIkeTunConnParams != null) {
profile.type = VpnProfile.TYPE_IKEV2_FROM_IKE_TUN_CONN_PARAMS;
return profile;
}
profile.type = mType;
profile.setAllowedAlgorithms(mAllowedAlgorithms);
switch (mType) { switch (mType) {
case TYPE_IKEV2_IPSEC_USER_PASS: case TYPE_IKEV2_IPSEC_USER_PASS:
profile.username = mUsername; profile.username = mUsername;
@@ -516,10 +549,47 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
@NonNull @NonNull
public static Ikev2VpnProfile fromVpnProfile(@NonNull VpnProfile profile) public static Ikev2VpnProfile fromVpnProfile(@NonNull VpnProfile profile)
throws GeneralSecurityException { throws GeneralSecurityException {
// TODO: Build the VpnProfile from mIkeTunConnParams if it exists. final Builder builder;
final Builder builder = new Builder(profile.server, profile.ipsecIdentifier); if (profile.ikeTunConnParams == null) {
builder = new Builder(profile.server, profile.ipsecIdentifier);
builder.setAllowedAlgorithms(profile.getAllowedAlgorithms());
switch (profile.type) {
case TYPE_IKEV2_IPSEC_USER_PASS:
builder.setAuthUsernamePassword(
profile.username,
profile.password,
certificateFromPemString(profile.ipsecCaCert));
break;
case TYPE_IKEV2_IPSEC_PSK:
builder.setAuthPsk(decodeFromIpsecSecret(profile.ipsecSecret));
break;
case TYPE_IKEV2_IPSEC_RSA:
final PrivateKey key;
if (profile.ipsecSecret.startsWith(PREFIX_KEYSTORE_ALIAS)) {
final String alias =
profile.ipsecSecret.substring(PREFIX_KEYSTORE_ALIAS.length());
key = getPrivateKeyFromAndroidKeystore(alias);
} else if (profile.ipsecSecret.startsWith(PREFIX_INLINE)) {
key = getPrivateKey(profile.ipsecSecret.substring(PREFIX_INLINE.length()));
} else {
throw new IllegalArgumentException("Invalid RSA private key prefix");
}
final X509Certificate userCert =
certificateFromPemString(profile.ipsecUserCert);
final X509Certificate serverRootCa =
certificateFromPemString(profile.ipsecCaCert);
builder.setAuthDigitalSignature(userCert, key, serverRootCa);
break;
default:
throw new IllegalArgumentException("Invalid auth method set");
}
} else {
builder = new Builder(profile.ikeTunConnParams);
}
builder.setProxy(profile.proxy); builder.setProxy(profile.proxy);
builder.setAllowedAlgorithms(profile.getAllowedAlgorithms());
builder.setBypassable(profile.isBypassable); builder.setBypassable(profile.isBypassable);
builder.setMetered(profile.isMetered); builder.setMetered(profile.isMetered);
builder.setMaxMtu(profile.maxMtu); builder.setMaxMtu(profile.maxMtu);
@@ -527,36 +597,6 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
builder.restrictToTestNetworks(); builder.restrictToTestNetworks();
} }
switch (profile.type) {
case TYPE_IKEV2_IPSEC_USER_PASS:
builder.setAuthUsernamePassword(
profile.username,
profile.password,
certificateFromPemString(profile.ipsecCaCert));
break;
case TYPE_IKEV2_IPSEC_PSK:
builder.setAuthPsk(decodeFromIpsecSecret(profile.ipsecSecret));
break;
case TYPE_IKEV2_IPSEC_RSA:
final PrivateKey key;
if (profile.ipsecSecret.startsWith(PREFIX_KEYSTORE_ALIAS)) {
final String alias =
profile.ipsecSecret.substring(PREFIX_KEYSTORE_ALIAS.length());
key = getPrivateKeyFromAndroidKeystore(alias);
} else if (profile.ipsecSecret.startsWith(PREFIX_INLINE)) {
key = getPrivateKey(profile.ipsecSecret.substring(PREFIX_INLINE.length()));
} else {
throw new IllegalArgumentException("Invalid RSA private key prefix");
}
final X509Certificate userCert = certificateFromPemString(profile.ipsecUserCert);
final X509Certificate serverRootCa = certificateFromPemString(profile.ipsecCaCert);
builder.setAuthDigitalSignature(userCert, key, serverRootCa);
break;
default:
throw new IllegalArgumentException("Invalid auth method set");
}
if (profile.excludeLocalRoutes && !profile.isBypassable) { if (profile.excludeLocalRoutes && !profile.isBypassable) {
Log.w(TAG, "ExcludeLocalRoutes should only be set in the bypassable VPN"); Log.w(TAG, "ExcludeLocalRoutes should only be set in the bypassable VPN");
} }
@@ -678,82 +718,13 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
} }
private static void checkBuilderSetter(boolean constructedFromIkeTunConParams, private static void checkBuilderSetter(boolean constructedFromIkeTunConParams,
@NonNull String message) { @NonNull String field) {
if (constructedFromIkeTunConParams) { if (constructedFromIkeTunConParams) {
throw new IllegalArgumentException("Constructed using IkeTunnelConnectionParams " throw new IllegalArgumentException(
+ "should not set " + message); field + " can't be set with IkeTunnelConnectionParams builder");
} }
} }
private static int getTypeFromIkeSession(@NonNull IkeSessionParams params) {
final IkeAuthConfig config = params.getLocalAuthConfig();
if (config instanceof IkeAuthDigitalSignLocalConfig) {
return TYPE_IKEV2_IPSEC_RSA;
} else if (config instanceof IkeAuthEapConfig) {
return TYPE_IKEV2_IPSEC_USER_PASS;
} else if (config instanceof IkeAuthPskConfig) {
return TYPE_IKEV2_IPSEC_PSK;
} else {
throw new IllegalStateException("Invalid local IkeAuthConfig");
}
}
@Nullable
private static String getPasswordFromIkeSession(@NonNull IkeSessionParams params) {
if (!(params.getLocalAuthConfig() instanceof IkeAuthEapConfig)) return null;
final IkeAuthEapConfig ikeAuthEapConfig = (IkeAuthEapConfig) params.getLocalAuthConfig();
final EapMsChapV2Config eapMsChapV2Config =
ikeAuthEapConfig.getEapConfig().getEapMsChapV2Config();
return (eapMsChapV2Config != null) ? eapMsChapV2Config.getPassword() : null;
}
@Nullable
private static String getUsernameFromIkeSession(@NonNull IkeSessionParams params) {
if (!(params.getLocalAuthConfig() instanceof IkeAuthEapConfig)) return null;
final IkeAuthEapConfig ikeAuthEapConfig = (IkeAuthEapConfig) params.getLocalAuthConfig();
final EapMsChapV2Config eapMsChapV2Config =
ikeAuthEapConfig.getEapConfig().getEapMsChapV2Config();
return (eapMsChapV2Config != null) ? eapMsChapV2Config.getUsername() : null;
}
@Nullable
private static X509Certificate getUserCertFromIkeSession(@NonNull IkeSessionParams params) {
if (!(params.getLocalAuthConfig() instanceof IkeAuthDigitalSignLocalConfig)) return null;
final IkeAuthDigitalSignLocalConfig config =
(IkeAuthDigitalSignLocalConfig) params.getLocalAuthConfig();
return config.getClientEndCertificate();
}
@Nullable
private static X509Certificate getServerRootCaCertFromIkeSession(
@NonNull IkeSessionParams params) {
if (!(params.getRemoteAuthConfig() instanceof IkeAuthDigitalSignRemoteConfig)) return null;
final IkeAuthDigitalSignRemoteConfig config =
(IkeAuthDigitalSignRemoteConfig) params.getRemoteAuthConfig();
return config.getRemoteCaCert();
}
@Nullable
private static PrivateKey getRsaPrivateKeyFromIkeSession(@NonNull IkeSessionParams params) {
if (!(params.getLocalAuthConfig() instanceof IkeAuthDigitalSignLocalConfig)) return null;
final IkeAuthDigitalSignLocalConfig config =
(IkeAuthDigitalSignLocalConfig) params.getLocalAuthConfig();
return config.getPrivateKey();
}
@Nullable
private static byte[] getPresharedKeyFromIkeSession(@NonNull IkeSessionParams params) {
if (!(params.getLocalAuthConfig() instanceof IkeAuthPskConfig)) return null;
final IkeAuthPskConfig config = (IkeAuthPskConfig) params.getLocalAuthConfig();
return config.getPsk();
}
@NonNull @NonNull
private static String getUserIdentityFromIkeSession(@NonNull IkeSessionParams params) { private static String getUserIdentityFromIkeSession(@NonNull IkeSessionParams params) {
final IkeIdentification ident = params.getLocalIdentification(); final IkeIdentification ident = params.getLocalIdentification();
@@ -768,6 +739,8 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
return ((IkeIpv4AddrIdentification) ident).ipv4Address.getHostAddress(); return ((IkeIpv4AddrIdentification) ident).ipv4Address.getHostAddress();
} else if (ident instanceof IkeIpv6AddrIdentification) { } else if (ident instanceof IkeIpv6AddrIdentification) {
return ((IkeIpv6AddrIdentification) ident).ipv6Address.getHostAddress(); return ((IkeIpv6AddrIdentification) ident).ipv6Address.getHostAddress();
} else if (ident instanceof IkeDerAsn1DnIdentification) {
throw new IllegalArgumentException("Unspported ASN.1 encoded identities");
} else { } else {
throw new IllegalArgumentException("Unknown IkeIdentification to get user identity"); throw new IllegalArgumentException("Unknown IkeIdentification to get user identity");
} }
@@ -776,8 +749,8 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
/** A incremental builder for IKEv2 VPN profiles */ /** A incremental builder for IKEv2 VPN profiles */
public static final class Builder { public static final class Builder {
private int mType = -1; private int mType = -1;
@NonNull private final String mServerAddr; @Nullable private final String mServerAddr;
@NonNull private final String mUserIdentity; @Nullable private final String mUserIdentity;
// PSK authentication // PSK authentication
@Nullable private byte[] mPresharedKey; @Nullable private byte[] mPresharedKey;
@@ -831,19 +804,8 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
checkNotNull(ikeTunConnParams, MISSING_PARAM_MSG_TMPL, "ikeTunConnParams"); checkNotNull(ikeTunConnParams, MISSING_PARAM_MSG_TMPL, "ikeTunConnParams");
mIkeTunConnParams = ikeTunConnParams; mIkeTunConnParams = ikeTunConnParams;
mServerAddr = null;
final IkeSessionParams ikeSessionParams = mIkeTunConnParams.getIkeSessionParams(); mUserIdentity = null;
mServerAddr = ikeSessionParams.getServerHostname();
mType = getTypeFromIkeSession(ikeSessionParams);
mUserCert = getUserCertFromIkeSession(ikeSessionParams);
mServerRootCaCert = getServerRootCaCertFromIkeSession(ikeSessionParams);
mRsaPrivateKey = getRsaPrivateKeyFromIkeSession(ikeSessionParams);
mServerRootCaCert = getServerRootCaCertFromIkeSession(ikeSessionParams);
mUsername = getUsernameFromIkeSession(ikeSessionParams);
mPassword = getPasswordFromIkeSession(ikeSessionParams);
mPresharedKey = getPresharedKeyFromIkeSession(ikeSessionParams);
mUserIdentity = getUserIdentityFromIkeSession(ikeSessionParams);
} }
private void resetAuthParams() { private void resetAuthParams() {
@@ -862,6 +824,10 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
* authentication method may be set. This method will overwrite any previously set * authentication method may be set. This method will overwrite any previously set
* authentication method. * authentication method.
* *
* <p>It's not allowed to set this if this {@link Builder} is constructed from an
* {@link IkeTunnelConnectionParams}. This information should be retrieved from
* {@link IkeTunnelConnectionParams}
*
* @param user the username to be used for EAP-MSCHAPv2 authentication * @param user the username to be used for EAP-MSCHAPv2 authentication
* @param pass the password to be used for EAP-MSCHAPv2 authentication * @param pass the password to be used for EAP-MSCHAPv2 authentication
* @param serverRootCa the root certificate to be used for verifying the identity of the * @param serverRootCa the root certificate to be used for verifying the identity of the
@@ -898,6 +864,10 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
* Only one authentication method may be set. This method will overwrite any previously set * Only one authentication method may be set. This method will overwrite any previously set
* authentication method. * authentication method.
* *
* <p>It's not allowed to set this if this {@link Builder} is constructed from an
* {@link IkeTunnelConnectionParams}. This information should be retrieved from
* {@link IkeTunnelConnectionParams}
*
* @param userCert the username to be used for RSA Digital signiture authentication * @param userCert the username to be used for RSA Digital signiture authentication
* @param key the PrivateKey instance associated with the user ceritificate, used for * @param key the PrivateKey instance associated with the user ceritificate, used for
* constructing the signature * constructing the signature
@@ -936,6 +906,10 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
* authentication method may be set. This method will overwrite any previously set * authentication method may be set. This method will overwrite any previously set
* authentication method. * authentication method.
* *
* <p>It's not allowed to set this if this {@link Builder} is constructed from an
* {@link IkeTunnelConnectionParams}. This information should be retrieved from
* {@link IkeTunnelConnectionParams}
*
* @param psk the key to be used for Pre-Shared Key authentication * @param psk the key to be used for Pre-Shared Key authentication
* @return this {@link Builder} object to facilitate chaining of method calls * @return this {@link Builder} object to facilitate chaining of method calls
*/ */
@@ -1068,6 +1042,10 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
* Authentication, and one that provides Encryption. Authenticated Encryption with * Authentication, and one that provides Encryption. Authenticated Encryption with
* Associated Data (AEAD) algorithms provide both Authentication and Encryption. * Associated Data (AEAD) algorithms provide both Authentication and Encryption.
* *
* <p>It's not allowed to set this if this {@link Builder} is constructed from an
* {@link IkeTunnelConnectionParams}. This information should be retrieved from
* {@link IkeTunnelConnectionParams}
*
* <p>By default, this profile will use any algorithm defined in {@link IpSecAlgorithm}, * <p>By default, this profile will use any algorithm defined in {@link IpSecAlgorithm},
* with the exception of those considered insecure (as described above). * with the exception of those considered insecure (as described above).
* *
@@ -1079,6 +1057,7 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
@RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
public Builder setAllowedAlgorithms(@NonNull List<String> algorithmNames) { public Builder setAllowedAlgorithms(@NonNull List<String> algorithmNames) {
checkNotNull(algorithmNames, MISSING_PARAM_MSG_TMPL, "algorithmNames"); checkNotNull(algorithmNames, MISSING_PARAM_MSG_TMPL, "algorithmNames");
checkBuilderSetter(mIkeTunConnParams != null, "algorithmNames");
validateAllowedAlgorithms(algorithmNames); validateAllowedAlgorithms(algorithmNames);
mAllowedAlgorithms = algorithmNames; mAllowedAlgorithms = algorithmNames;

View File

@@ -22,12 +22,17 @@ import android.net.Ikev2VpnProfile;
import android.net.PlatformVpnProfile; import android.net.PlatformVpnProfile;
import android.net.ProxyInfo; import android.net.ProxyInfo;
import android.net.Uri; import android.net.Uri;
import android.net.ipsec.ike.IkeTunnelConnectionParams;
import android.net.vcn.persistablebundleutils.TunnelConnectionParamsUtils;
import android.os.Build; import android.os.Build;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import android.os.PersistableBundle;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.HexDump;
import com.android.net.module.util.ProxyUtils; import com.android.net.module.util.ProxyUtils;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
@@ -69,7 +74,8 @@ public final class VpnProfile implements Cloneable, Parcelable {
public static final int TYPE_IKEV2_IPSEC_USER_PASS = 6; public static final int TYPE_IKEV2_IPSEC_USER_PASS = 6;
public static final int TYPE_IKEV2_IPSEC_PSK = 7; public static final int TYPE_IKEV2_IPSEC_PSK = 7;
public static final int TYPE_IKEV2_IPSEC_RSA = 8; public static final int TYPE_IKEV2_IPSEC_RSA = 8;
public static final int TYPE_MAX = 8; public static final int TYPE_IKEV2_FROM_IKE_TUN_CONN_PARAMS = 9;
public static final int TYPE_MAX = 9;
// Match these constants with R.array.vpn_proxy_settings. // Match these constants with R.array.vpn_proxy_settings.
public static final int PROXY_NONE = 0; public static final int PROXY_NONE = 0;
@@ -145,25 +151,27 @@ public final class VpnProfile implements Cloneable, Parcelable {
public final boolean excludeLocalRoutes; // 25 public final boolean excludeLocalRoutes; // 25
public final boolean requiresInternetValidation; // 26 public final boolean requiresInternetValidation; // 26
public final IkeTunnelConnectionParams ikeTunConnParams; // 27
// Helper fields. // Helper fields.
@UnsupportedAppUsage @UnsupportedAppUsage
public transient boolean saveLogin = false; public transient boolean saveLogin = false;
public VpnProfile(String key) { public VpnProfile(String key) {
this(key, false, false, false); this(key, false, false, false, null);
} }
public VpnProfile(String key, boolean isRestrictedToTestNetworks) { public VpnProfile(String key, boolean isRestrictedToTestNetworks) {
this(key, isRestrictedToTestNetworks, false, false); this(key, isRestrictedToTestNetworks, false, false, null);
} }
public VpnProfile(String key, boolean isRestrictedToTestNetworks, boolean excludeLocalRoutes, public VpnProfile(String key, boolean isRestrictedToTestNetworks, boolean excludeLocalRoutes,
boolean requiresInternetValidation) { boolean requiresInternetValidation, IkeTunnelConnectionParams ikeTunConnParams) {
this.key = key; this.key = key;
this.isRestrictedToTestNetworks = isRestrictedToTestNetworks; this.isRestrictedToTestNetworks = isRestrictedToTestNetworks;
this.excludeLocalRoutes = excludeLocalRoutes; this.excludeLocalRoutes = excludeLocalRoutes;
this.requiresInternetValidation = requiresInternetValidation; this.requiresInternetValidation = requiresInternetValidation;
this.ikeTunConnParams = ikeTunConnParams;
} }
@UnsupportedAppUsage @UnsupportedAppUsage
@@ -195,6 +203,10 @@ public final class VpnProfile implements Cloneable, Parcelable {
isRestrictedToTestNetworks = in.readBoolean(); isRestrictedToTestNetworks = in.readBoolean();
excludeLocalRoutes = in.readBoolean(); excludeLocalRoutes = in.readBoolean();
requiresInternetValidation = in.readBoolean(); requiresInternetValidation = in.readBoolean();
final PersistableBundle bundle =
in.readParcelable(PersistableBundle.class.getClassLoader());
ikeTunConnParams = (bundle == null) ? null
: TunnelConnectionParamsUtils.fromPersistableBundle(bundle);
} }
/** /**
@@ -244,6 +256,8 @@ public final class VpnProfile implements Cloneable, Parcelable {
out.writeBoolean(isRestrictedToTestNetworks); out.writeBoolean(isRestrictedToTestNetworks);
out.writeBoolean(excludeLocalRoutes); out.writeBoolean(excludeLocalRoutes);
out.writeBoolean(requiresInternetValidation); out.writeBoolean(requiresInternetValidation);
out.writeParcelable(ikeTunConnParams == null ? null
: TunnelConnectionParamsUtils.toPersistableBundle(ikeTunConnParams), flags);
} }
/** /**
@@ -259,15 +273,17 @@ public final class VpnProfile implements Cloneable, Parcelable {
} }
String[] values = new String(value, StandardCharsets.UTF_8).split(VALUE_DELIMITER, -1); String[] values = new String(value, StandardCharsets.UTF_8).split(VALUE_DELIMITER, -1);
// Acceptable numbers of values are: // Acceptable numbers of values are:
// 14-19: Standard profile, with option for serverCert, proxy // 14-19: Standard profile, with option for serverCert, proxy
// 24: Standard profile with serverCert, proxy and platform-VPN parameters // 24: Standard profile with serverCert, proxy and platform-VPN parameters
// 25: Standard profile with platform-VPN parameters and isRestrictedToTestNetworks // 25: Standard profile with platform-VPN parameters and isRestrictedToTestNetworks
// 26: ...and excludeLocalRoutes // 26: ...and excludeLocalRoutes
// (26 can only be found on dogfood devices)
// 27: ...and requiresInternetValidation // 27: ...and requiresInternetValidation
// (26,27 can only be found on dogfood devices)
// 28: ...and ikeTunConnParams
if ((values.length < 14 || (values.length > 19 && values.length < 24) if ((values.length < 14 || (values.length > 19 && values.length < 24)
|| values.length > 27)) { || values.length > 28)) {
return null; return null;
} }
@@ -292,8 +308,22 @@ public final class VpnProfile implements Cloneable, Parcelable {
requiresInternetValidation = false; requiresInternetValidation = false;
} }
final IkeTunnelConnectionParams tempIkeTunConnParams;
// Assign null directly if the ikeTunConParams field is empty.
if (values.length >= 28 && values[27].length() != 0) {
final Parcel parcel = Parcel.obtain();
final byte[] bytes = HexDump.hexStringToByteArray(values[27]);
parcel.unmarshall(bytes, 0, bytes.length);
parcel.setDataPosition(0);
final PersistableBundle bundle = (PersistableBundle) parcel.readValue(
PersistableBundle.class.getClassLoader());
tempIkeTunConnParams = TunnelConnectionParamsUtils.fromPersistableBundle(bundle);
} else {
tempIkeTunConnParams = null;
}
VpnProfile profile = new VpnProfile(key, isRestrictedToTestNetworks, VpnProfile profile = new VpnProfile(key, isRestrictedToTestNetworks,
excludeLocalRoutes, requiresInternetValidation); excludeLocalRoutes, requiresInternetValidation, tempIkeTunConnParams);
profile.name = values[0]; profile.name = values[0];
profile.type = Integer.parseInt(values[1]); profile.type = Integer.parseInt(values[1]);
if (profile.type < 0 || profile.type > TYPE_MAX) { if (profile.type < 0 || profile.type > TYPE_MAX) {
@@ -345,6 +375,7 @@ public final class VpnProfile implements Cloneable, Parcelable {
profile.saveLogin = !profile.username.isEmpty() || !profile.password.isEmpty(); profile.saveLogin = !profile.username.isEmpty() || !profile.password.isEmpty();
return profile; return profile;
} catch (Exception e) { } catch (Exception e) {
Log.d(TAG, "Got exception in decode.", e);
// ignore // ignore
} }
return null; return null;
@@ -406,6 +437,17 @@ public final class VpnProfile implements Cloneable, Parcelable {
builder.append(VALUE_DELIMITER).append(excludeLocalRoutes); builder.append(VALUE_DELIMITER).append(excludeLocalRoutes);
builder.append(VALUE_DELIMITER).append(requiresInternetValidation); builder.append(VALUE_DELIMITER).append(requiresInternetValidation);
if (ikeTunConnParams != null) {
final PersistableBundle bundle =
TunnelConnectionParamsUtils.toPersistableBundle(ikeTunConnParams);
final Parcel parcel = Parcel.obtain();
parcel.writeValue(bundle);
final byte[] bytes = parcel.marshall();
builder.append(VALUE_DELIMITER).append(HexDump.toHexString(bytes));
} else {
builder.append(VALUE_DELIMITER).append("");
}
return builder.toString().getBytes(StandardCharsets.UTF_8); return builder.toString().getBytes(StandardCharsets.UTF_8);
} }
@@ -486,7 +528,8 @@ public final class VpnProfile implements Cloneable, Parcelable {
key, type, server, username, password, dnsServers, searchDomains, routes, mppe, key, type, server, username, password, dnsServers, searchDomains, routes, mppe,
l2tpSecret, ipsecIdentifier, ipsecSecret, ipsecUserCert, ipsecCaCert, ipsecServerCert, l2tpSecret, ipsecIdentifier, ipsecSecret, ipsecUserCert, ipsecCaCert, ipsecServerCert,
proxy, mAllowedAlgorithms, isBypassable, isMetered, maxMtu, areAuthParamsInline, proxy, mAllowedAlgorithms, isBypassable, isMetered, maxMtu, areAuthParamsInline,
isRestrictedToTestNetworks, excludeLocalRoutes, requiresInternetValidation); isRestrictedToTestNetworks, excludeLocalRoutes, requiresInternetValidation,
ikeTunConnParams);
} }
/** Checks VPN profiles for interior equality. */ /** Checks VPN profiles for interior equality. */
@@ -521,7 +564,8 @@ public final class VpnProfile implements Cloneable, Parcelable {
&& areAuthParamsInline == other.areAuthParamsInline && areAuthParamsInline == other.areAuthParamsInline
&& isRestrictedToTestNetworks == other.isRestrictedToTestNetworks && isRestrictedToTestNetworks == other.isRestrictedToTestNetworks
&& excludeLocalRoutes == other.excludeLocalRoutes && excludeLocalRoutes == other.excludeLocalRoutes
&& requiresInternetValidation == other.requiresInternetValidation; && requiresInternetValidation == other.requiresInternetValidation
&& Objects.equals(ikeTunConnParams, other.ikeTunConnParams);
} }
@NonNull @NonNull