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

Commit 48160f9b authored by Chiachang Wang's avatar Chiachang Wang Committed by Gerrit Code Review
Browse files

Merge "Ignore other IKE options if IkeTunnelConnectionParams is set"

parents e8869375 3cb07d73
Loading
Loading
Loading
Loading
+132 −153
Original line number Diff line number Diff line
@@ -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.CRYPT_AES_CBC;
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.util.Preconditions.checkStringNotEmpty;
@@ -40,6 +34,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresFeature;
import android.content.pm.PackageManager;
import android.net.ipsec.ike.IkeDerAsn1DnIdentification;
import android.net.ipsec.ike.IkeFqdnIdentification;
import android.net.ipsec.ike.IkeIdentification;
import android.net.ipsec.ike.IkeIpv4AddrIdentification;
@@ -119,8 +114,8 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
        DEFAULT_ALGORITHMS = Collections.unmodifiableList(algorithms);
    }

    @NonNull private final String mServerAddr;
    @NonNull private final String mUserIdentity;
    @Nullable private final String mServerAddr;
    @Nullable private final String mUserIdentity;

    // PSK authentication
    @Nullable private final byte[] mPresharedKey;
@@ -146,8 +141,8 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {

    private Ikev2VpnProfile(
            int type,
            @NonNull String serverAddr,
            @NonNull String userIdentity,
            @Nullable String serverAddr,
            @Nullable String userIdentity,
            @Nullable byte[] presharedKey,
            @Nullable X509Certificate serverRootCaCert,
            @Nullable String username,
@@ -165,8 +160,6 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
            @Nullable IkeTunnelConnectionParams ikeTunConnParams) {
        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");

        mServerAddr = serverAddr;
@@ -191,18 +184,12 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
        mIsMetered = isMetered;
        mMaxMtu = maxMtu;
        mIsRestrictedToTestNetworks = restrictToTestNetworks;

        mIkeTunConnParams = ikeTunConnParams;

        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
        // networks, the VPN must provide a link fulfilling the stricter of the two conditions
        // (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);
        }

        // 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) {
            case TYPE_IKEV2_IPSEC_USER_PASS:
                checkNotNull(mUsername, MISSING_PARAM_MSG_TMPL, "Username");
@@ -286,22 +282,31 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
    /** Retrieves the server address string. */
    @NonNull
    public String getServerAddr() {
        return mServerAddr;
        if (mIkeTunConnParams == null) return mServerAddr;

        final IkeSessionParams ikeSessionParams = mIkeTunConnParams.getIkeSessionParams();
        return ikeSessionParams.getServerHostname();
    }

    /** Retrieves the user identity. */
    @NonNull
    public String getUserIdentity() {
        return mUserIdentity;
        if (mIkeTunConnParams == null) return mUserIdentity;

        final IkeSessionParams ikeSessionParams = mIkeTunConnParams.getIkeSessionParams();
        return getUserIdentityFromIkeSession(ikeSessionParams);
    }

    /**
     * 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
    public byte[] getPresharedKey() {
        if (mIkeTunConnParams != null) return null;

        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.
     *
     * <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
    public X509Certificate getServerRootCaCert() {
        if (mIkeTunConnParams != null) return null;

        return mServerRootCaCert;
    }

    /**
     * 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
    public String getUsername() {
        if (mIkeTunConnParams != null) return null;

        return mUsername;
    }

    /**
     * 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
    public String getPassword() {
        if (mIkeTunConnParams != null) return null;

        return mPassword;
    }

    /**
     * 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
    public PrivateKey getRsaPrivateKey() {
        if (mIkeTunConnParams != null) return null;

        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
    public X509Certificate getUserCert() {
        if (mIkeTunConnParams != null) return null;

        return mUserCert;
    }

@@ -358,9 +379,14 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
        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
    public List<String> getAllowedAlgorithms() {
        if (mIkeTunConnParams != null) return new ArrayList<>();

        return mAllowedAlgorithms;
    }

@@ -455,18 +481,25 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
    @NonNull
    public VpnProfile toVpnProfile() throws IOException, GeneralSecurityException {
        final VpnProfile profile = new VpnProfile("" /* Key; value unused by IKEv2VpnProfile(s) */,
                mIsRestrictedToTestNetworks, mExcludeLocalRoutes, mRequiresInternetValidation);
        profile.type = mType;
        profile.server = mServerAddr;
        profile.ipsecIdentifier = mUserIdentity;
                mIsRestrictedToTestNetworks, mExcludeLocalRoutes, mRequiresInternetValidation,
                mIkeTunConnParams);

        profile.server = getServerAddr();
        profile.ipsecIdentifier = getUserIdentity();
        profile.proxy = mProxyInfo;
        profile.setAllowedAlgorithms(mAllowedAlgorithms);
        profile.isBypassable = mIsBypassable;
        profile.isMetered = mIsMetered;
        profile.maxMtu = mMaxMtu;
        profile.areAuthParamsInline = 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) {
            case TYPE_IKEV2_IPSEC_USER_PASS:
                profile.username = mUsername;
@@ -516,16 +549,10 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
    @NonNull
    public static Ikev2VpnProfile fromVpnProfile(@NonNull VpnProfile profile)
            throws GeneralSecurityException {
        // TODO: Build the VpnProfile from mIkeTunConnParams if it exists.
        final Builder builder = new Builder(profile.server, profile.ipsecIdentifier);
        builder.setProxy(profile.proxy);
        final Builder builder;
        if (profile.ikeTunConnParams == null) {
            builder = new Builder(profile.server, profile.ipsecIdentifier);
            builder.setAllowedAlgorithms(profile.getAllowedAlgorithms());
        builder.setBypassable(profile.isBypassable);
        builder.setMetered(profile.isMetered);
        builder.setMaxMtu(profile.maxMtu);
        if (profile.isRestrictedToTestNetworks) {
            builder.restrictToTestNetworks();
        }

            switch (profile.type) {
                case TYPE_IKEV2_IPSEC_USER_PASS:
@@ -549,13 +576,26 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
                        throw new IllegalArgumentException("Invalid RSA private key prefix");
                    }

                final X509Certificate userCert = certificateFromPemString(profile.ipsecUserCert);
                final X509Certificate serverRootCa = certificateFromPemString(profile.ipsecCaCert);
                    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.setBypassable(profile.isBypassable);
        builder.setMetered(profile.isMetered);
        builder.setMaxMtu(profile.maxMtu);
        if (profile.isRestrictedToTestNetworks) {
            builder.restrictToTestNetworks();
        }

        if (profile.excludeLocalRoutes && !profile.isBypassable) {
            Log.w(TAG, "ExcludeLocalRoutes should only be set in the bypassable VPN");
@@ -678,80 +718,11 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
    }

    private static void checkBuilderSetter(boolean constructedFromIkeTunConParams,
            @NonNull String message) {
            @NonNull String field) {
        if (constructedFromIkeTunConParams) {
            throw new IllegalArgumentException("Constructed using IkeTunnelConnectionParams "
                    + "should not set " + message);
        }
    }

    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();
            throw new IllegalArgumentException(
                    field + " can't be set with IkeTunnelConnectionParams builder");
        }

    @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
@@ -768,6 +739,8 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
            return ((IkeIpv4AddrIdentification) ident).ipv4Address.getHostAddress();
        } else if (ident instanceof IkeIpv6AddrIdentification) {
            return ((IkeIpv6AddrIdentification) ident).ipv6Address.getHostAddress();
        } else if (ident instanceof IkeDerAsn1DnIdentification) {
            throw new IllegalArgumentException("Unspported ASN.1 encoded identities");
        } else {
            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 */
    public static final class Builder {
        private int mType = -1;
        @NonNull private final String mServerAddr;
        @NonNull private final String mUserIdentity;
        @Nullable private final String mServerAddr;
        @Nullable private final String mUserIdentity;

        // PSK authentication
        @Nullable private byte[] mPresharedKey;
@@ -831,19 +804,8 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
            checkNotNull(ikeTunConnParams, MISSING_PARAM_MSG_TMPL, "ikeTunConnParams");

            mIkeTunConnParams = ikeTunConnParams;

            final IkeSessionParams ikeSessionParams = mIkeTunConnParams.getIkeSessionParams();
            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);
            mServerAddr = null;
            mUserIdentity = null;
        }

        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.
         *
         * <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 pass the password to be used for EAP-MSCHAPv2 authentication
         * @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
         * 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 key the PrivateKey instance associated with the user ceritificate, used for
         *     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.
         *
         * <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
         * @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
         * 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},
         * 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)
        public Builder setAllowedAlgorithms(@NonNull List<String> algorithmNames) {
            checkNotNull(algorithmNames, MISSING_PARAM_MSG_TMPL, "algorithmNames");
            checkBuilderSetter(mIkeTunConnParams != null, "algorithmNames");
            validateAllowedAlgorithms(algorithmNames);

            mAllowedAlgorithms = algorithmNames;
+53 −9

File changed.

Preview size limit exceeded, changes collapsed.