1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.net;
18 
19 import static android.net.IpSecAlgorithm.AUTH_AES_CMAC;
20 import static android.net.IpSecAlgorithm.AUTH_AES_XCBC;
21 import static android.net.IpSecAlgorithm.AUTH_CRYPT_AES_GCM;
22 import static android.net.IpSecAlgorithm.AUTH_CRYPT_CHACHA20_POLY1305;
23 import static android.net.IpSecAlgorithm.AUTH_HMAC_SHA256;
24 import static android.net.IpSecAlgorithm.AUTH_HMAC_SHA384;
25 import static android.net.IpSecAlgorithm.AUTH_HMAC_SHA512;
26 import static android.net.IpSecAlgorithm.CRYPT_AES_CBC;
27 import static android.net.IpSecAlgorithm.CRYPT_AES_CTR;
28 
29 import static com.android.internal.annotations.VisibleForTesting.Visibility;
30 import static com.android.internal.util.Preconditions.checkStringNotEmpty;
31 import static com.android.net.module.util.NetworkStackConstants.IPV6_MIN_MTU;
32 
33 import android.annotation.NonNull;
34 import android.annotation.Nullable;
35 import android.annotation.RequiresFeature;
36 import android.content.pm.PackageManager;
37 import android.net.ipsec.ike.IkeDerAsn1DnIdentification;
38 import android.net.ipsec.ike.IkeFqdnIdentification;
39 import android.net.ipsec.ike.IkeIdentification;
40 import android.net.ipsec.ike.IkeIpv4AddrIdentification;
41 import android.net.ipsec.ike.IkeIpv6AddrIdentification;
42 import android.net.ipsec.ike.IkeKeyIdIdentification;
43 import android.net.ipsec.ike.IkeRfc822AddrIdentification;
44 import android.net.ipsec.ike.IkeSessionParams;
45 import android.net.ipsec.ike.IkeTunnelConnectionParams;
46 import android.security.Credentials;
47 import android.util.Log;
48 
49 import com.android.internal.annotations.VisibleForTesting;
50 import com.android.internal.net.VpnProfile;
51 
52 import java.io.IOException;
53 import java.nio.charset.StandardCharsets;
54 import java.security.GeneralSecurityException;
55 import java.security.Key;
56 import java.security.KeyFactory;
57 import java.security.KeyStore;
58 import java.security.NoSuchAlgorithmException;
59 import java.security.PrivateKey;
60 import java.security.cert.CertificateEncodingException;
61 import java.security.cert.CertificateException;
62 import java.security.cert.X509Certificate;
63 import java.security.spec.InvalidKeySpecException;
64 import java.security.spec.PKCS8EncodedKeySpec;
65 import java.util.ArrayList;
66 import java.util.Arrays;
67 import java.util.Base64;
68 import java.util.Collections;
69 import java.util.List;
70 import java.util.Objects;
71 
72 /**
73  * The Ikev2VpnProfile is a configuration for the platform setup of IKEv2/IPsec VPNs.
74  *
75  * <p>Together with VpnManager, this allows apps to provision IKEv2/IPsec VPNs that do not require
76  * the VPN app to constantly run in the background.
77  *
78  * @see VpnManager
79  * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3.2">RFC 7296 - Internet Key
80  *     Exchange, Version 2 (IKEv2)</a>
81  */
82 public final class Ikev2VpnProfile extends PlatformVpnProfile {
83     private static final String TAG = Ikev2VpnProfile.class.getSimpleName();
84     /** Prefix for when a Private Key is an alias to look for in KeyStore @hide */
85     public static final String PREFIX_KEYSTORE_ALIAS = "KEYSTORE_ALIAS:";
86     /** Prefix for when a Private Key is stored directly in the profile @hide */
87     public static final String PREFIX_INLINE = "INLINE:";
88 
89     private static final String ANDROID_KEYSTORE_PROVIDER = "AndroidKeyStore";
90     private static final String MISSING_PARAM_MSG_TMPL = "Required parameter was not provided: %s";
91     private static final String EMPTY_CERT = "";
92 
93     /** @hide */
94     public static final List<String> DEFAULT_ALGORITHMS;
95 
addAlgorithmIfSupported(List<String> algorithms, String ipSecAlgoName)96     private static void addAlgorithmIfSupported(List<String> algorithms, String ipSecAlgoName) {
97         if (IpSecAlgorithm.getSupportedAlgorithms().contains(ipSecAlgoName)) {
98             algorithms.add(ipSecAlgoName);
99         }
100     }
101 
102     static {
103         final List<String> algorithms = new ArrayList<>();
addAlgorithmIfSupported(algorithms, CRYPT_AES_CBC)104         addAlgorithmIfSupported(algorithms, CRYPT_AES_CBC);
addAlgorithmIfSupported(algorithms, CRYPT_AES_CTR)105         addAlgorithmIfSupported(algorithms, CRYPT_AES_CTR);
addAlgorithmIfSupported(algorithms, AUTH_HMAC_SHA256)106         addAlgorithmIfSupported(algorithms, AUTH_HMAC_SHA256);
addAlgorithmIfSupported(algorithms, AUTH_HMAC_SHA384)107         addAlgorithmIfSupported(algorithms, AUTH_HMAC_SHA384);
addAlgorithmIfSupported(algorithms, AUTH_HMAC_SHA512)108         addAlgorithmIfSupported(algorithms, AUTH_HMAC_SHA512);
addAlgorithmIfSupported(algorithms, AUTH_AES_XCBC)109         addAlgorithmIfSupported(algorithms, AUTH_AES_XCBC);
addAlgorithmIfSupported(algorithms, AUTH_AES_CMAC)110         addAlgorithmIfSupported(algorithms, AUTH_AES_CMAC);
addAlgorithmIfSupported(algorithms, AUTH_CRYPT_AES_GCM)111         addAlgorithmIfSupported(algorithms, AUTH_CRYPT_AES_GCM);
addAlgorithmIfSupported(algorithms, AUTH_CRYPT_CHACHA20_POLY1305)112         addAlgorithmIfSupported(algorithms, AUTH_CRYPT_CHACHA20_POLY1305);
113 
114         DEFAULT_ALGORITHMS = Collections.unmodifiableList(algorithms);
115     }
116 
117     @Nullable private final String mServerAddr;
118     @Nullable private final String mUserIdentity;
119 
120     // PSK authentication
121     @Nullable private final byte[] mPresharedKey;
122 
123     // Username/Password, RSA authentication
124     @Nullable private final X509Certificate mServerRootCaCert;
125 
126     // Username/Password authentication
127     @Nullable private final String mUsername;
128     @Nullable private final String mPassword;
129 
130     // RSA Certificate authentication
131     @Nullable private final PrivateKey mRsaPrivateKey;
132     @Nullable private final X509Certificate mUserCert;
133 
134     @Nullable private final ProxyInfo mProxyInfo;
135     @NonNull private final List<String> mAllowedAlgorithms;
136     private final boolean mIsBypassable; // Defaults in builder
137     private final boolean mIsMetered; // Defaults in builder
138     private final int mMaxMtu; // Defaults in builder
139     private final boolean mIsRestrictedToTestNetworks;
140     @Nullable private final IkeTunnelConnectionParams mIkeTunConnParams;
141     private final boolean mAutomaticNattKeepaliveTimerEnabled;
142     private final boolean mAutomaticIpVersionSelectionEnabled;
143 
Ikev2VpnProfile( int type, @Nullable String serverAddr, @Nullable String userIdentity, @Nullable byte[] presharedKey, @Nullable X509Certificate serverRootCaCert, @Nullable String username, @Nullable String password, @Nullable PrivateKey rsaPrivateKey, @Nullable X509Certificate userCert, @Nullable ProxyInfo proxyInfo, @NonNull List<String> allowedAlgorithms, boolean isBypassable, boolean isMetered, int maxMtu, boolean restrictToTestNetworks, boolean excludeLocalRoutes, boolean requiresInternetValidation, @Nullable IkeTunnelConnectionParams ikeTunConnParams, boolean automaticNattKeepaliveTimerEnabled, boolean automaticIpVersionSelectionEnabled)144     private Ikev2VpnProfile(
145             int type,
146             @Nullable String serverAddr,
147             @Nullable String userIdentity,
148             @Nullable byte[] presharedKey,
149             @Nullable X509Certificate serverRootCaCert,
150             @Nullable String username,
151             @Nullable String password,
152             @Nullable PrivateKey rsaPrivateKey,
153             @Nullable X509Certificate userCert,
154             @Nullable ProxyInfo proxyInfo,
155             @NonNull List<String> allowedAlgorithms,
156             boolean isBypassable,
157             boolean isMetered,
158             int maxMtu,
159             boolean restrictToTestNetworks,
160             boolean excludeLocalRoutes,
161             boolean requiresInternetValidation,
162             @Nullable IkeTunnelConnectionParams ikeTunConnParams,
163             boolean automaticNattKeepaliveTimerEnabled,
164             boolean automaticIpVersionSelectionEnabled) {
165         super(type, excludeLocalRoutes, requiresInternetValidation);
166 
167         checkNotNull(allowedAlgorithms, MISSING_PARAM_MSG_TMPL, "Allowed Algorithms");
168 
169         mServerAddr = serverAddr;
170         mUserIdentity = userIdentity;
171         mPresharedKey =
172                 presharedKey == null ? null : Arrays.copyOf(presharedKey, presharedKey.length);
173         mServerRootCaCert = serverRootCaCert;
174         mUsername = username;
175         mPassword = password;
176         mRsaPrivateKey = rsaPrivateKey;
177         mUserCert = userCert;
178         mProxyInfo = (proxyInfo == null) ? null : new ProxyInfo(proxyInfo);
179 
180         // UnmodifiableList doesn't make a defensive copy by default.
181         mAllowedAlgorithms = Collections.unmodifiableList(new ArrayList<>(allowedAlgorithms));
182         if (excludeLocalRoutes && !isBypassable) {
183             throw new IllegalArgumentException(
184                     "Vpn must be bypassable if excludeLocalRoutes is set");
185         }
186 
187         mIsBypassable = isBypassable;
188         mIsMetered = isMetered;
189         mMaxMtu = maxMtu;
190         mIsRestrictedToTestNetworks = restrictToTestNetworks;
191         mIkeTunConnParams = ikeTunConnParams;
192         mAutomaticNattKeepaliveTimerEnabled = automaticNattKeepaliveTimerEnabled;
193         mAutomaticIpVersionSelectionEnabled = automaticIpVersionSelectionEnabled;
194 
195         validate();
196     }
197 
validate()198     private void validate() {
199         // IPv6 MTU is greater; since profiles may be started by the system on IPv4 and IPv6
200         // networks, the VPN must provide a link fulfilling the stricter of the two conditions
201         // (at least that of the IPv6 MTU).
202         if (mMaxMtu < IPV6_MIN_MTU) {
203             throw new IllegalArgumentException("Max MTU must be at least" + IPV6_MIN_MTU);
204         }
205 
206         // Skip validating the other fields if mIkeTunConnParams is set because the required
207         // information should all come from the mIkeTunConnParams.
208         if (mIkeTunConnParams != null) return;
209 
210         // Server Address not validated except to check an address was provided. This allows for
211         // dual-stack servers and hostname based addresses.
212         checkStringNotEmpty(mServerAddr, MISSING_PARAM_MSG_TMPL, "Server Address");
213         checkStringNotEmpty(mUserIdentity, MISSING_PARAM_MSG_TMPL, "User Identity");
214 
215         switch (mType) {
216             case TYPE_IKEV2_IPSEC_USER_PASS:
217                 checkNotNull(mUsername, MISSING_PARAM_MSG_TMPL, "Username");
218                 checkNotNull(mPassword, MISSING_PARAM_MSG_TMPL, "Password");
219 
220                 if (mServerRootCaCert != null) checkCert(mServerRootCaCert);
221 
222                 break;
223             case TYPE_IKEV2_IPSEC_PSK:
224                 checkNotNull(mPresharedKey, MISSING_PARAM_MSG_TMPL, "Preshared Key");
225                 break;
226             case TYPE_IKEV2_IPSEC_RSA:
227                 checkNotNull(mUserCert, MISSING_PARAM_MSG_TMPL, "User cert");
228                 checkNotNull(mRsaPrivateKey, MISSING_PARAM_MSG_TMPL, "RSA Private key");
229 
230                 checkCert(mUserCert);
231                 if (mServerRootCaCert != null) checkCert(mServerRootCaCert);
232 
233                 break;
234             default:
235                 throw new IllegalArgumentException("Invalid auth method set");
236         }
237 
238         validateAllowedAlgorithms(mAllowedAlgorithms);
239     }
240 
241     /**
242      * Validates that the allowed algorithms are a valid set for IPsec purposes
243      *
244      * <p>In order for the algorithm list to be a valid set, it must contain at least one algorithm
245      * that provides Authentication, and one that provides Encryption. Authenticated Encryption with
246      * Associated Data (AEAD) algorithms are counted as providing Authentication and Encryption.
247      *
248      * @param algorithmNames The list to be validated
249      */
validateAllowedAlgorithms(@onNull List<String> algorithmNames)250     private static void validateAllowedAlgorithms(@NonNull List<String> algorithmNames) {
251         // First, make sure no insecure algorithms were proposed.
252         if (algorithmNames.contains(IpSecAlgorithm.AUTH_HMAC_MD5)
253                 || algorithmNames.contains(IpSecAlgorithm.AUTH_HMAC_SHA1)) {
254             throw new IllegalArgumentException("Algorithm not supported for IKEv2 VPN profiles");
255         }
256 
257         // Validate that some valid combination (AEAD or AUTH + CRYPT) is present
258         if (hasAeadAlgorithms(algorithmNames) || hasNormalModeAlgorithms(algorithmNames)) {
259             return;
260         }
261 
262         throw new IllegalArgumentException("Algorithm set missing support for Auth, Crypt or both");
263     }
264 
265     /**
266      * Checks if the provided list has AEAD algorithms
267      *
268      * @hide
269      */
hasAeadAlgorithms(@onNull List<String> algorithmNames)270     public static boolean hasAeadAlgorithms(@NonNull List<String> algorithmNames) {
271         return algorithmNames.contains(IpSecAlgorithm.AUTH_CRYPT_AES_GCM);
272     }
273 
274     /**
275      * Checks the provided list has acceptable (non-AEAD) authentication and encryption algorithms
276      *
277      * @hide
278      */
hasNormalModeAlgorithms(@onNull List<String> algorithmNames)279     public static boolean hasNormalModeAlgorithms(@NonNull List<String> algorithmNames) {
280         final boolean hasCrypt = algorithmNames.contains(IpSecAlgorithm.CRYPT_AES_CBC);
281         final boolean hasAuth = algorithmNames.contains(IpSecAlgorithm.AUTH_HMAC_SHA256)
282                 || algorithmNames.contains(IpSecAlgorithm.AUTH_HMAC_SHA384)
283                 || algorithmNames.contains(IpSecAlgorithm.AUTH_HMAC_SHA512);
284 
285         return hasCrypt && hasAuth;
286     }
287 
288     /** Retrieves the server address string. */
289     @NonNull
getServerAddr()290     public String getServerAddr() {
291         if (mIkeTunConnParams == null) return mServerAddr;
292 
293         final IkeSessionParams ikeSessionParams = mIkeTunConnParams.getIkeSessionParams();
294         return ikeSessionParams.getServerHostname();
295     }
296 
297     /** Retrieves the user identity. */
298     @NonNull
getUserIdentity()299     public String getUserIdentity() {
300         if (mIkeTunConnParams == null) return mUserIdentity;
301 
302         final IkeSessionParams ikeSessionParams = mIkeTunConnParams.getIkeSessionParams();
303         return getUserIdentityFromIkeSession(ikeSessionParams);
304     }
305 
306     /**
307      * Retrieves the pre-shared key.
308      *
309      * <p>May be null if the profile is not using Pre-shared key authentication, or the profile is
310      * built from an {@link IkeTunnelConnectionParams}.
311      */
312     @Nullable
getPresharedKey()313     public byte[] getPresharedKey() {
314         if (mIkeTunConnParams != null) return null;
315 
316         return mPresharedKey == null ? null : Arrays.copyOf(mPresharedKey, mPresharedKey.length);
317     }
318 
319     /**
320      * Retrieves the certificate for the server's root CA.
321      *
322      * <p>May be null if the profile is not using RSA Digital Signature Authentication or
323      * Username/Password authentication, or the profile is built from an
324      * {@link IkeTunnelConnectionParams}.
325      */
326     @Nullable
getServerRootCaCert()327     public X509Certificate getServerRootCaCert() {
328         if (mIkeTunConnParams != null) return null;
329 
330         return mServerRootCaCert;
331     }
332     /**
333      * Retrieves the username.
334      *
335      * <p>May be null if the profile is not using Username/Password authentication, or the profile
336      * is built from an {@link IkeTunnelConnectionParams}.
337      */
338     @Nullable
getUsername()339     public String getUsername() {
340         if (mIkeTunConnParams != null) return null;
341 
342         return mUsername;
343     }
344 
345     /**
346      * Retrieves the password.
347      *
348      * <p>May be null if the profile is not using Username/Password authentication, or the profile
349      * is built from an {@link IkeTunnelConnectionParams}.
350      */
351     @Nullable
getPassword()352     public String getPassword() {
353         if (mIkeTunConnParams != null) return null;
354 
355         return mPassword;
356     }
357 
358     /**
359      * Retrieves the RSA private key.
360      *
361      * <p>May be null if the profile is not using RSA Digital Signature authentication, or the
362      * profile is built from an {@link IkeTunnelConnectionParams}.
363      */
364     @Nullable
getRsaPrivateKey()365     public PrivateKey getRsaPrivateKey() {
366         if (mIkeTunConnParams != null) return null;
367 
368         return mRsaPrivateKey;
369     }
370 
371     /** Retrieves the user certificate, if any was set.
372      *
373      * <p>May be null if the profile is built from an {@link IkeTunnelConnectionParams}.
374      */
375     @Nullable
getUserCert()376     public X509Certificate getUserCert() {
377         if (mIkeTunConnParams != null) return null;
378 
379         return mUserCert;
380     }
381 
382     /** Retrieves the proxy information if any was set */
383     @Nullable
getProxyInfo()384     public ProxyInfo getProxyInfo() {
385         return mProxyInfo;
386     }
387 
388     /** Returns all the algorithms allowed by this VPN profile.
389      *
390      *  <p>May be an empty list if the profile is built from an {@link IkeTunnelConnectionParams}.
391      */
392     @NonNull
getAllowedAlgorithms()393     public List<String> getAllowedAlgorithms() {
394         if (mIkeTunConnParams != null) return new ArrayList<>();
395 
396         return mAllowedAlgorithms;
397     }
398 
399     /** Returns whether or not the VPN profile should be bypassable. */
isBypassable()400     public boolean isBypassable() {
401         return mIsBypassable;
402     }
403 
404     /** Returns whether or not the VPN profile should be always considered metered. */
isMetered()405     public boolean isMetered() {
406         return mIsMetered;
407     }
408 
409     /** Retrieves the maximum MTU set for this VPN profile. */
getMaxMtu()410     public int getMaxMtu() {
411         return mMaxMtu;
412     }
413 
414     /** Retrieves the ikeTunnelConnectionParams contains IKEv2 configurations, if any was set. */
415     @Nullable
getIkeTunnelConnectionParams()416     public IkeTunnelConnectionParams getIkeTunnelConnectionParams() {
417         return mIkeTunConnParams;
418     }
419 
420     /**
421      * Returns whether or not this VPN profile is restricted to test networks.
422      *
423      * @hide
424      */
isRestrictedToTestNetworks()425     public boolean isRestrictedToTestNetworks() {
426         return mIsRestrictedToTestNetworks;
427     }
428 
429     /** Returns whether automatic NAT-T keepalive timers are enabled. */
isAutomaticNattKeepaliveTimerEnabled()430     public boolean isAutomaticNattKeepaliveTimerEnabled() {
431         return mAutomaticNattKeepaliveTimerEnabled;
432     }
433 
434     /** Returns whether automatic IP version selection is enabled. */
isAutomaticIpVersionSelectionEnabled()435     public boolean isAutomaticIpVersionSelectionEnabled() {
436         return mAutomaticIpVersionSelectionEnabled;
437     }
438 
439     @Override
hashCode()440     public int hashCode() {
441         return Objects.hash(
442                 mType,
443                 mServerAddr,
444                 mUserIdentity,
445                 Arrays.hashCode(mPresharedKey),
446                 mServerRootCaCert,
447                 mUsername,
448                 mPassword,
449                 mRsaPrivateKey,
450                 mUserCert,
451                 mProxyInfo,
452                 mAllowedAlgorithms,
453                 mIsBypassable,
454                 mIsMetered,
455                 mMaxMtu,
456                 mIsRestrictedToTestNetworks,
457                 mExcludeLocalRoutes,
458                 mRequiresInternetValidation,
459                 mIkeTunConnParams,
460                 mAutomaticNattKeepaliveTimerEnabled,
461                 mAutomaticIpVersionSelectionEnabled);
462     }
463 
464     @Override
equals(@ullable Object obj)465     public boolean equals(@Nullable Object obj) {
466         if (!(obj instanceof Ikev2VpnProfile)) {
467             return false;
468         }
469 
470         final Ikev2VpnProfile other = (Ikev2VpnProfile) obj;
471         return mType == other.mType
472                 && Objects.equals(mServerAddr, other.mServerAddr)
473                 && Objects.equals(mUserIdentity, other.mUserIdentity)
474                 && Arrays.equals(mPresharedKey, other.mPresharedKey)
475                 && Objects.equals(mServerRootCaCert, other.mServerRootCaCert)
476                 && Objects.equals(mUsername, other.mUsername)
477                 && Objects.equals(mPassword, other.mPassword)
478                 && Objects.equals(mRsaPrivateKey, other.mRsaPrivateKey)
479                 && Objects.equals(mUserCert, other.mUserCert)
480                 && Objects.equals(mProxyInfo, other.mProxyInfo)
481                 && Objects.equals(mAllowedAlgorithms, other.mAllowedAlgorithms)
482                 && mIsBypassable == other.mIsBypassable
483                 && mIsMetered == other.mIsMetered
484                 && mMaxMtu == other.mMaxMtu
485                 && mIsRestrictedToTestNetworks == other.mIsRestrictedToTestNetworks
486                 && mExcludeLocalRoutes == other.mExcludeLocalRoutes
487                 && mRequiresInternetValidation == other.mRequiresInternetValidation
488                 && Objects.equals(mIkeTunConnParams, other.mIkeTunConnParams)
489                 && mAutomaticNattKeepaliveTimerEnabled == other.mAutomaticNattKeepaliveTimerEnabled
490                 && mAutomaticIpVersionSelectionEnabled == other.mAutomaticIpVersionSelectionEnabled;
491     }
492 
493     /**
494      * Builds a VpnProfile instance for internal use, based on the stored IKEv2/IPsec parameters.
495      *
496      * <p>Redundant authentication information (from previous calls to other setAuth* methods) will
497      * be discarded.
498      *
499      * @hide
500      */
501     @NonNull
toVpnProfile()502     public VpnProfile toVpnProfile() throws IOException, GeneralSecurityException {
503         final VpnProfile profile = new VpnProfile("" /* Key; value unused by IKEv2VpnProfile(s) */,
504                 mIsRestrictedToTestNetworks, mExcludeLocalRoutes, mRequiresInternetValidation,
505                 mIkeTunConnParams, mAutomaticNattKeepaliveTimerEnabled,
506                 mAutomaticIpVersionSelectionEnabled);
507         profile.proxy = mProxyInfo;
508         profile.isBypassable = mIsBypassable;
509         profile.isMetered = mIsMetered;
510         profile.maxMtu = mMaxMtu;
511         profile.areAuthParamsInline = true;
512         profile.saveLogin = true;
513         // The other fields should come from mIkeTunConnParams if it's available.
514         if (mIkeTunConnParams != null) {
515             profile.type = VpnProfile.TYPE_IKEV2_FROM_IKE_TUN_CONN_PARAMS;
516             return profile;
517         }
518 
519         profile.type = mType;
520         profile.server = getServerAddr();
521         profile.ipsecIdentifier = getUserIdentity();
522         profile.setAllowedAlgorithms(mAllowedAlgorithms);
523         switch (mType) {
524             case TYPE_IKEV2_IPSEC_USER_PASS:
525                 profile.username = mUsername;
526                 profile.password = mPassword;
527                 profile.ipsecCaCert =
528                         mServerRootCaCert == null ? "" : certificateToPemString(mServerRootCaCert);
529                 break;
530             case TYPE_IKEV2_IPSEC_PSK:
531                 profile.ipsecSecret = encodeForIpsecSecret(mPresharedKey);
532                 break;
533             case TYPE_IKEV2_IPSEC_RSA:
534                 profile.ipsecUserCert = certificateToPemString(mUserCert);
535                 profile.ipsecSecret =
536                         PREFIX_INLINE + encodeForIpsecSecret(mRsaPrivateKey.getEncoded());
537                 profile.ipsecCaCert =
538                         mServerRootCaCert == null ? "" : certificateToPemString(mServerRootCaCert);
539                 break;
540             default:
541                 throw new IllegalArgumentException("Invalid auth method set");
542         }
543 
544         return profile;
545     }
546 
getPrivateKeyFromAndroidKeystore(String alias)547     private static PrivateKey getPrivateKeyFromAndroidKeystore(String alias) {
548         try {
549             final KeyStore keystore = KeyStore.getInstance(ANDROID_KEYSTORE_PROVIDER);
550             keystore.load(null);
551             final Key key = keystore.getKey(alias, null);
552             if (!(key instanceof PrivateKey)) {
553                 throw new IllegalStateException(
554                         "Unexpected key type returned from android keystore.");
555             }
556             return (PrivateKey) key;
557         } catch (Exception e) {
558             throw new IllegalStateException("Failed to load key from android keystore.", e);
559         }
560     }
561 
562     /**
563      * Builds the Ikev2VpnProfile from the given profile.
564      *
565      * @param profile the source VpnProfile to build from
566      * @return The IKEv2/IPsec VPN profile
567      * @hide
568      */
569     @NonNull
fromVpnProfile(@onNull VpnProfile profile)570     public static Ikev2VpnProfile fromVpnProfile(@NonNull VpnProfile profile)
571             throws GeneralSecurityException {
572         final Builder builder;
573         if (profile.ikeTunConnParams == null) {
574             builder = new Builder(profile.server, profile.ipsecIdentifier);
575             builder.setAllowedAlgorithms(profile.getAllowedAlgorithms());
576 
577             switch (profile.type) {
578                 case TYPE_IKEV2_IPSEC_USER_PASS:
579                     builder.setAuthUsernamePassword(
580                             profile.username,
581                             profile.password,
582                             certificateFromPemString(profile.ipsecCaCert));
583                     break;
584                 case TYPE_IKEV2_IPSEC_PSK:
585                     builder.setAuthPsk(decodeFromIpsecSecret(profile.ipsecSecret));
586                     break;
587                 case TYPE_IKEV2_IPSEC_RSA:
588                     final PrivateKey key;
589                     if (profile.ipsecSecret.startsWith(PREFIX_KEYSTORE_ALIAS)) {
590                         final String alias =
591                                 profile.ipsecSecret.substring(PREFIX_KEYSTORE_ALIAS.length());
592                         key = getPrivateKeyFromAndroidKeystore(alias);
593                     } else if (profile.ipsecSecret.startsWith(PREFIX_INLINE)) {
594                         key = getPrivateKey(profile.ipsecSecret.substring(PREFIX_INLINE.length()));
595                     } else {
596                         throw new IllegalArgumentException("Invalid RSA private key prefix");
597                     }
598 
599                     final X509Certificate userCert =
600                             certificateFromPemString(profile.ipsecUserCert);
601                     final X509Certificate serverRootCa =
602                             certificateFromPemString(profile.ipsecCaCert);
603                     builder.setAuthDigitalSignature(userCert, key, serverRootCa);
604                     break;
605                 default:
606                     throw new IllegalArgumentException("Invalid auth method set");
607             }
608         } else {
609             builder = new Builder(profile.ikeTunConnParams);
610         }
611 
612         builder.setProxy(profile.proxy);
613         builder.setBypassable(profile.isBypassable);
614         builder.setMetered(profile.isMetered);
615         builder.setMaxMtu(profile.maxMtu);
616         if (profile.isRestrictedToTestNetworks) {
617             builder.restrictToTestNetworks();
618         }
619 
620         if (profile.excludeLocalRoutes && !profile.isBypassable) {
621             Log.w(TAG, "ExcludeLocalRoutes should only be set in the bypassable VPN");
622         }
623 
624         builder.setLocalRoutesExcluded(profile.excludeLocalRoutes && profile.isBypassable);
625         builder.setRequiresInternetValidation(profile.requiresInternetValidation);
626 
627         builder.setAutomaticNattKeepaliveTimerEnabled(profile.automaticNattKeepaliveTimerEnabled);
628         builder.setAutomaticIpVersionSelectionEnabled(profile.automaticIpVersionSelectionEnabled);
629 
630         return builder.build();
631     }
632 
633     /**
634      * Validates that the VpnProfile is acceptable for the purposes of an Ikev2VpnProfile.
635      *
636      * @hide
637      */
isValidVpnProfile(@onNull VpnProfile profile)638     public static boolean isValidVpnProfile(@NonNull VpnProfile profile) {
639         if (profile.server.isEmpty() || profile.ipsecIdentifier.isEmpty()) {
640             return false;
641         }
642 
643         switch (profile.type) {
644             case TYPE_IKEV2_IPSEC_USER_PASS:
645                 if (profile.username.isEmpty() || profile.password.isEmpty()) {
646                     return false;
647                 }
648                 break;
649             case TYPE_IKEV2_IPSEC_PSK:
650                 if (profile.ipsecSecret.isEmpty()) {
651                     return false;
652                 }
653                 break;
654             case TYPE_IKEV2_IPSEC_RSA:
655                 if (profile.ipsecSecret.isEmpty() || profile.ipsecUserCert.isEmpty()) {
656                     return false;
657                 }
658                 break;
659             default:
660                 return false;
661         }
662 
663         return true;
664     }
665 
666     /**
667      * Converts a X509 Certificate to a PEM-formatted string.
668      *
669      * <p>Must be public due to runtime-package restrictions.
670      *
671      * @hide
672      */
673     @NonNull
674     @VisibleForTesting(visibility = Visibility.PRIVATE)
certificateToPemString(@ullable X509Certificate cert)675     public static String certificateToPemString(@Nullable X509Certificate cert)
676             throws IOException, CertificateEncodingException {
677         if (cert == null) {
678             return EMPTY_CERT;
679         }
680 
681         // Credentials.convertToPem outputs ASCII bytes.
682         return new String(Credentials.convertToPem(cert), StandardCharsets.US_ASCII);
683     }
684 
685     /**
686      * Decodes the provided Certificate(s).
687      *
688      * <p>Will use the first one if the certStr encodes more than one certificate.
689      */
690     @Nullable
certificateFromPemString(@ullable String certStr)691     private static X509Certificate certificateFromPemString(@Nullable String certStr)
692             throws CertificateException {
693         if (certStr == null || EMPTY_CERT.equals(certStr)) {
694             return null;
695         }
696 
697         try {
698             final List<X509Certificate> certs =
699                     Credentials.convertFromPem(certStr.getBytes(StandardCharsets.US_ASCII));
700             return certs.isEmpty() ? null : certs.get(0);
701         } catch (IOException e) {
702             throw new CertificateException(e);
703         }
704     }
705 
706     /** @hide */
707     @NonNull
encodeForIpsecSecret(@onNull byte[] secret)708     public static String encodeForIpsecSecret(@NonNull byte[] secret) {
709         checkNotNull(secret, MISSING_PARAM_MSG_TMPL, "secret");
710 
711         return Base64.getEncoder().encodeToString(secret);
712     }
713 
714     @NonNull
decodeFromIpsecSecret(@onNull String encoded)715     private static byte[] decodeFromIpsecSecret(@NonNull String encoded) {
716         checkNotNull(encoded, MISSING_PARAM_MSG_TMPL, "encoded");
717 
718         return Base64.getDecoder().decode(encoded);
719     }
720 
721     @NonNull
getPrivateKey(@onNull String keyStr)722     private static PrivateKey getPrivateKey(@NonNull String keyStr)
723             throws InvalidKeySpecException, NoSuchAlgorithmException {
724         final PKCS8EncodedKeySpec privateKeySpec =
725                 new PKCS8EncodedKeySpec(decodeFromIpsecSecret(keyStr));
726         final KeyFactory keyFactory = KeyFactory.getInstance("RSA");
727         return keyFactory.generatePrivate(privateKeySpec);
728     }
729 
checkCert(@onNull X509Certificate cert)730     private static void checkCert(@NonNull X509Certificate cert) {
731         try {
732             certificateToPemString(cert);
733         } catch (GeneralSecurityException | IOException e) {
734             throw new IllegalArgumentException("Certificate could not be encoded");
735         }
736     }
737 
checkNotNull( final T reference, final String messageTemplate, final Object... messageArgs)738     private static @NonNull <T> T checkNotNull(
739             final T reference, final String messageTemplate, final Object... messageArgs) {
740         return Objects.requireNonNull(reference, String.format(messageTemplate, messageArgs));
741     }
742 
checkBuilderSetter(boolean constructedFromIkeTunConParams, @NonNull String field)743     private static void checkBuilderSetter(boolean constructedFromIkeTunConParams,
744             @NonNull String field) {
745         if (constructedFromIkeTunConParams) {
746             throw new IllegalArgumentException(
747                     field + " can't be set with IkeTunnelConnectionParams builder");
748         }
749     }
750 
751     @NonNull
getUserIdentityFromIkeSession(@onNull IkeSessionParams params)752     private static String getUserIdentityFromIkeSession(@NonNull IkeSessionParams params) {
753         final IkeIdentification ident = params.getLocalIdentification();
754         // Refer to VpnIkev2Utils.parseIkeIdentification().
755         if (ident instanceof IkeKeyIdIdentification) {
756             return "@#" + new String(((IkeKeyIdIdentification) ident).keyId);
757         } else if (ident instanceof IkeRfc822AddrIdentification) {
758             return "@@" + ((IkeRfc822AddrIdentification) ident).rfc822Name;
759         } else if (ident instanceof IkeFqdnIdentification) {
760             return "@" + ((IkeFqdnIdentification) ident).fqdn;
761         } else if (ident instanceof IkeIpv4AddrIdentification) {
762             return ((IkeIpv4AddrIdentification) ident).ipv4Address.getHostAddress();
763         } else if (ident instanceof IkeIpv6AddrIdentification) {
764             return ((IkeIpv6AddrIdentification) ident).ipv6Address.getHostAddress();
765         } else if (ident instanceof IkeDerAsn1DnIdentification) {
766             throw new IllegalArgumentException("Unspported ASN.1 encoded identities");
767         } else {
768             throw new IllegalArgumentException("Unknown IkeIdentification to get user identity");
769         }
770     }
771 
772     @Override
toString()773     public String toString() {
774         final StringBuilder sb = new StringBuilder("IkeV2VpnProfile [");
775         sb.append(" MaxMtu=" + mMaxMtu);
776         if (mIsBypassable) sb.append(" Bypassable");
777         if (mRequiresInternetValidation) sb.append(" RequiresInternetValidation");
778         if (mIsRestrictedToTestNetworks) sb.append(" RestrictedToTestNetworks");
779         if (mAutomaticNattKeepaliveTimerEnabled) sb.append(" AutomaticNattKeepaliveTimerEnabled");
780         if (mAutomaticIpVersionSelectionEnabled) sb.append(" AutomaticIpVersionSelectionEnabled");
781         sb.append("]");
782         return sb.toString();
783     }
784 
785     /** A incremental builder for IKEv2 VPN profiles */
786     public static final class Builder {
787         private int mType = -1;
788         @Nullable private final String mServerAddr;
789         @Nullable private final String mUserIdentity;
790 
791         // PSK authentication
792         @Nullable private byte[] mPresharedKey;
793 
794         // Username/Password, RSA authentication
795         @Nullable private X509Certificate mServerRootCaCert;
796 
797         // Username/Password authentication
798         @Nullable private String mUsername;
799         @Nullable private String mPassword;
800 
801         // RSA Certificate authentication
802         @Nullable private PrivateKey mRsaPrivateKey;
803         @Nullable private X509Certificate mUserCert;
804 
805         @Nullable private ProxyInfo mProxyInfo;
806         @NonNull private List<String> mAllowedAlgorithms = DEFAULT_ALGORITHMS;
807         private boolean mRequiresInternetValidation = false;
808         private boolean mIsBypassable = false;
809         private boolean mIsMetered = true;
810         private int mMaxMtu = PlatformVpnProfile.MAX_MTU_DEFAULT;
811         private boolean mIsRestrictedToTestNetworks = false;
812         private boolean mExcludeLocalRoutes = false;
813         private boolean mAutomaticNattKeepaliveTimerEnabled = false;
814         private boolean mAutomaticIpVersionSelectionEnabled = false;
815         @Nullable private final IkeTunnelConnectionParams mIkeTunConnParams;
816 
817         /**
818          * Creates a new builder with the basic parameters of an IKEv2/IPsec VPN.
819          *
820          * @param serverAddr the server that the VPN should connect to
821          * @param identity the identity string to be used for IKEv2 authentication
822          */
823         @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
Builder(@onNull String serverAddr, @NonNull String identity)824         public Builder(@NonNull String serverAddr, @NonNull String identity) {
825             checkNotNull(serverAddr, MISSING_PARAM_MSG_TMPL, "serverAddr");
826             checkNotNull(identity, MISSING_PARAM_MSG_TMPL, "identity");
827 
828             mServerAddr = serverAddr;
829             mUserIdentity = identity;
830 
831             mIkeTunConnParams = null;
832         }
833 
834         /**
835          * Creates a new builder from a {@link IkeTunnelConnectionParams}
836          *
837          * @param ikeTunConnParams the {@link IkeTunnelConnectionParams} contains IKEv2
838          *                         configurations
839          */
840         @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
Builder(@onNull IkeTunnelConnectionParams ikeTunConnParams)841         public Builder(@NonNull IkeTunnelConnectionParams ikeTunConnParams) {
842             checkNotNull(ikeTunConnParams, MISSING_PARAM_MSG_TMPL, "ikeTunConnParams");
843 
844             mIkeTunConnParams = ikeTunConnParams;
845             mServerAddr = null;
846             mUserIdentity = null;
847         }
848 
resetAuthParams()849         private void resetAuthParams() {
850             mPresharedKey = null;
851             mServerRootCaCert = null;
852             mUsername = null;
853             mPassword = null;
854             mRsaPrivateKey = null;
855             mUserCert = null;
856         }
857 
858         /**
859          * Set the IKEv2 authentication to use the provided username/password.
860          *
861          * <p>Setting this will configure IKEv2 authentication using EAP-MSCHAPv2. Only one
862          * authentication method may be set. This method will overwrite any previously set
863          * authentication method.
864          *
865          * <p>If this {@link Builder} is constructed with an {@link IkeTunnelConnectionParams},
866          * authentication details should be configured there, and calling this method will result
867          * in an exception being thrown.
868          *
869          * @param user the username to be used for EAP-MSCHAPv2 authentication
870          * @param pass the password to be used for EAP-MSCHAPv2 authentication
871          * @param serverRootCa the root certificate to be used for verifying the identity of the
872          *     server
873          * @return this {@link Builder} object to facilitate chaining of method calls
874          * @throws IllegalArgumentException if any of the certificates were invalid or of an
875          *     unrecognized format
876          */
877         @NonNull
878         @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
setAuthUsernamePassword( @onNull String user, @NonNull String pass, @Nullable X509Certificate serverRootCa)879         public Builder setAuthUsernamePassword(
880                 @NonNull String user,
881                 @NonNull String pass,
882                 @Nullable X509Certificate serverRootCa) {
883             checkNotNull(user, MISSING_PARAM_MSG_TMPL, "user");
884             checkNotNull(pass, MISSING_PARAM_MSG_TMPL, "pass");
885             checkBuilderSetter(mIkeTunConnParams != null, "authUsernamePassword");
886 
887             // Test to make sure all auth params can be encoded safely.
888             if (serverRootCa != null) checkCert(serverRootCa);
889 
890             resetAuthParams();
891             mUsername = user;
892             mPassword = pass;
893             mServerRootCaCert = serverRootCa;
894             mType = VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS;
895             return this;
896         }
897 
898         /**
899          * Set the IKEv2 authentication to use Digital Signature Authentication with the given key.
900          *
901          * <p>Setting this will configure IKEv2 authentication using a Digital Signature scheme.
902          * Only one authentication method may be set. This method will overwrite any previously set
903          * authentication method.
904          *
905          * <p>If this {@link Builder} is constructed with an {@link IkeTunnelConnectionParams},
906          * authentication details should be configured there, and calling this method will result in
907          * an exception being thrown.
908          *
909          * @param userCert the username to be used for RSA Digital signiture authentication
910          * @param key the PrivateKey instance associated with the user ceritificate, used for
911          *     constructing the signature
912          * @param serverRootCa the root certificate to be used for verifying the identity of the
913          *     server
914          * @return this {@link Builder} object to facilitate chaining of method calls
915          * @throws IllegalArgumentException if any of the certificates were invalid or of an
916          *     unrecognized format
917          */
918         @NonNull
919         @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
setAuthDigitalSignature( @onNull X509Certificate userCert, @NonNull PrivateKey key, @Nullable X509Certificate serverRootCa)920         public Builder setAuthDigitalSignature(
921                 @NonNull X509Certificate userCert,
922                 @NonNull PrivateKey key,
923                 @Nullable X509Certificate serverRootCa) {
924             checkNotNull(userCert, MISSING_PARAM_MSG_TMPL, "userCert");
925             checkNotNull(key, MISSING_PARAM_MSG_TMPL, "key");
926             checkBuilderSetter(mIkeTunConnParams != null, "authDigitalSignature");
927 
928             // Test to make sure all auth params can be encoded safely.
929             checkCert(userCert);
930             if (serverRootCa != null) checkCert(serverRootCa);
931 
932             resetAuthParams();
933             mUserCert = userCert;
934             mRsaPrivateKey = key;
935             mServerRootCaCert = serverRootCa;
936             mType = VpnProfile.TYPE_IKEV2_IPSEC_RSA;
937             return this;
938         }
939 
940         /**
941          * Set the IKEv2 authentication to use Preshared keys.
942          *
943          * <p>Setting this will configure IKEv2 authentication using a Preshared Key. Only one
944          * authentication method may be set. This method will overwrite any previously set
945          * authentication method.
946          *
947          * <p>If this {@link Builder} is constructed with an {@link IkeTunnelConnectionParams},
948          * authentication details should be configured there, and calling this method will result in
949          * an exception being thrown.
950          *
951          * @param psk the key to be used for Pre-Shared Key authentication
952          * @return this {@link Builder} object to facilitate chaining of method calls
953          */
954         @NonNull
955         @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
setAuthPsk(@onNull byte[] psk)956         public Builder setAuthPsk(@NonNull byte[] psk) {
957             checkNotNull(psk, MISSING_PARAM_MSG_TMPL, "psk");
958             checkBuilderSetter(mIkeTunConnParams != null, "authPsk");
959 
960             resetAuthParams();
961             mPresharedKey = psk;
962             mType = VpnProfile.TYPE_IKEV2_IPSEC_PSK;
963             return this;
964         }
965 
966         /**
967          * Sets whether apps can bypass this VPN connection.
968          *
969          * <p>By default, all traffic from apps are forwarded through the VPN interface and it is
970          * not possible for unprivileged apps to side-step the VPN. If a VPN is set to bypassable,
971          * apps may use methods such as {@link Network#getSocketFactory} or {@link
972          * Network#openConnection} to instead send/receive directly over the underlying network or
973          * any other network they have permissions for.
974          *
975          * @param isBypassable Whether or not the VPN should be considered bypassable. Defaults to
976          *     {@code false}.
977          * @return this {@link Builder} object to facilitate chaining of method calls
978          */
979         @NonNull
980         @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
setBypassable(boolean isBypassable)981         public Builder setBypassable(boolean isBypassable) {
982             mIsBypassable = isBypassable;
983             return this;
984         }
985 
986         /**
987          * Sets a proxy for the VPN network.
988          *
989          * <p>Note that this proxy is only a recommendation and it may be ignored by apps.
990          *
991          * @param proxy the ProxyInfo to be set for the VPN network
992          * @return this {@link Builder} object to facilitate chaining of method calls
993          */
994         @NonNull
995         @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
setProxy(@ullable ProxyInfo proxy)996         public Builder setProxy(@Nullable ProxyInfo proxy) {
997             mProxyInfo = proxy;
998             return this;
999         }
1000 
1001         /**
1002          * Set the upper bound of the maximum transmission unit (MTU) of the VPN interface.
1003          *
1004          * <p>If it is not set, a safe value will be used. Additionally, the actual link MTU will be
1005          * dynamically calculated/updated based on the underlying link's mtu.
1006          *
1007          * @param mtu the MTU (in bytes) of the VPN interface
1008          * @return this {@link Builder} object to facilitate chaining of method calls
1009          * @throws IllegalArgumentException if the value is not at least the minimum IPv6 MTU (1280)
1010          */
1011         @NonNull
1012         @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
setMaxMtu(int mtu)1013         public Builder setMaxMtu(int mtu) {
1014             // IPv6 MTU is greater; since profiles may be started by the system on IPv4 and IPv6
1015             // networks, the VPN must provide a link fulfilling the stricter of the two conditions
1016             // (at least that of the IPv6 MTU).
1017             if (mtu < IPV6_MIN_MTU) {
1018                 throw new IllegalArgumentException("Max MTU must be at least " + IPV6_MIN_MTU);
1019             }
1020             mMaxMtu = mtu;
1021             return this;
1022         }
1023 
1024         /**
1025          * Request that this VPN undergoes Internet validation.
1026          *
1027          * If this is true, the platform will perform basic validation checks for Internet
1028          * connectivity over this VPN. If and when they succeed, the VPN network capabilities will
1029          * reflect this by gaining the {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED}
1030          * capability.
1031          *
1032          * If this is false, the platform assumes the VPN either is always capable of reaching the
1033          * Internet or intends not to. In this case, the VPN network capabilities will
1034          * always gain the {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED} capability
1035          * immediately after it connects, whether it can reach public Internet destinations or not.
1036          *
1037          * @param requiresInternetValidation {@code true} if the framework should attempt to
1038          *                                   validate this VPN for Internet connectivity. Defaults
1039          *                                   to {@code false}.
1040          */
1041         @NonNull
1042         @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
setRequiresInternetValidation(boolean requiresInternetValidation)1043         public Builder setRequiresInternetValidation(boolean requiresInternetValidation) {
1044             mRequiresInternetValidation = requiresInternetValidation;
1045             return this;
1046         }
1047 
1048         /**
1049          * Marks the VPN network as metered.
1050          *
1051          * <p>A VPN network is classified as metered when the user is sensitive to heavy data usage
1052          * due to monetary costs and/or data limitations. In such cases, you should set this to
1053          * {@code true} so that apps on the system can avoid doing large data transfers. Otherwise,
1054          * set this to {@code false}. Doing so would cause VPN network to inherit its meteredness
1055          * from the underlying network.
1056          *
1057          * @param isMetered {@code true} if the VPN network should be treated as metered regardless
1058          *     of underlying network meteredness. Defaults to {@code true}.
1059          * @return this {@link Builder} object to facilitate chaining of method calls
1060          * @see NetworkCapabilities#NET_CAPABILITY_NOT_METERED
1061          */
1062         @NonNull
1063         @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
setMetered(boolean isMetered)1064         public Builder setMetered(boolean isMetered) {
1065             mIsMetered = isMetered;
1066             return this;
1067         }
1068 
1069         /**
1070          * Sets the allowable set of IPsec algorithms
1071          *
1072          * <p>If set, this will constrain the set of algorithms that the IPsec tunnel will use for
1073          * integrity verification and encryption to the provided list.
1074          *
1075          * <p>The set of allowed IPsec algorithms is defined in {@link IpSecAlgorithm}. Adding of
1076          * algorithms that are considered insecure (such as AUTH_HMAC_MD5 and AUTH_HMAC_SHA1) is not
1077          * permitted, and will result in an IllegalArgumentException being thrown.
1078          *
1079          * <p>The provided algorithm list must contain at least one algorithm that provides
1080          * Authentication, and one that provides Encryption. Authenticated Encryption with
1081          * Associated Data (AEAD) algorithms provide both Authentication and Encryption.
1082          *
1083          * <p>If this {@link Builder} is constructed with an {@link IkeTunnelConnectionParams},
1084          * authentication details should be configured there, and calling this method will result in
1085          * an exception being thrown.
1086          *
1087          * <p>By default, this profile will use any algorithm defined in {@link IpSecAlgorithm},
1088          * with the exception of those considered insecure (as described above).
1089          *
1090          * @param algorithmNames the list of supported IPsec algorithms
1091          * @return this {@link Builder} object to facilitate chaining of method calls
1092          * @see IpSecAlgorithm
1093          */
1094         @NonNull
1095         @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
setAllowedAlgorithms(@onNull List<String> algorithmNames)1096         public Builder setAllowedAlgorithms(@NonNull List<String> algorithmNames) {
1097             checkNotNull(algorithmNames, MISSING_PARAM_MSG_TMPL, "algorithmNames");
1098             checkBuilderSetter(mIkeTunConnParams != null, "algorithmNames");
1099             validateAllowedAlgorithms(algorithmNames);
1100 
1101             mAllowedAlgorithms = algorithmNames;
1102             return this;
1103         }
1104 
1105         /**
1106          * Restricts this profile to use test networks (only).
1107          *
1108          * <p>This method is for testing only, and must not be used by apps. Calling
1109          * provisionVpnProfile() with a profile where test-network usage is enabled will require the
1110          * MANAGE_TEST_NETWORKS permission.
1111          *
1112          * @hide
1113          */
1114         @NonNull
1115         @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
restrictToTestNetworks()1116         public Builder restrictToTestNetworks() {
1117             mIsRestrictedToTestNetworks = true;
1118             return this;
1119         }
1120 
1121         /**
1122          * Sets the enabled state of the automatic NAT-T keepalive timers
1123          *
1124          * Note that if this builder was constructed with a {@link IkeTunnelConnectionParams},
1125          * but this is called with {@code true}, the framework will automatically choose the
1126          * appropriate keepalive timer and ignore the settings in the session params embedded
1127          * in the connection params.
1128          *
1129          * @param isEnabled {@code true} to enable automatic keepalive timers, based on internal
1130          *     platform signals. Defaults to {@code false}.
1131          * @return this {@link Builder} object to facilitate chaining of method calls
1132          */
1133         @NonNull
1134         @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
setAutomaticNattKeepaliveTimerEnabled(boolean isEnabled)1135         public Builder setAutomaticNattKeepaliveTimerEnabled(boolean isEnabled) {
1136             mAutomaticNattKeepaliveTimerEnabled = isEnabled;
1137             return this;
1138         }
1139 
1140         /**
1141          * Sets the enabled state of the automatic IP version selection
1142          *
1143          * @param isEnabled {@code true} to enable automatic IP version selection, based on internal
1144          *     platform signals. Defaults to {@code false}.
1145          * @return this {@link Builder} object to facilitate chaining of method calls
1146          */
1147         @NonNull
1148         @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
setAutomaticIpVersionSelectionEnabled(boolean isEnabled)1149         public Builder setAutomaticIpVersionSelectionEnabled(boolean isEnabled) {
1150             mAutomaticIpVersionSelectionEnabled = isEnabled;
1151             return this;
1152         }
1153 
1154         /**
1155          * Sets whether the local traffic is exempted from the VPN.
1156          *
1157          * When this is set, the system will not use the VPN network when an app
1158          * tries to send traffic for an IP address that is on a local network.
1159          *
1160          * Note that there are important security implications. In particular, the
1161          * networks that the device connects to typically decides what IP addresses
1162          * are part of the local network. This means that for VPNs setting this
1163          * flag, it is possible for anybody to set up a public network in such a
1164          * way that traffic to arbitrary IP addresses will bypass the VPN, including
1165          * traffic to services like DNS. When using this API, please consider the
1166          * security implications for your particular case.
1167          *
1168          * Note that because the local traffic will always bypass the VPN,
1169          * it is not possible to set this flag on a non-bypassable VPN.
1170          */
1171         @NonNull
1172         @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
setLocalRoutesExcluded(boolean excludeLocalRoutes)1173         public Builder setLocalRoutesExcluded(boolean excludeLocalRoutes) {
1174             mExcludeLocalRoutes = excludeLocalRoutes;
1175             return this;
1176         }
1177 
1178         /**
1179          * Validates, builds and provisions the VpnProfile.
1180          *
1181          * @throws IllegalArgumentException if any of the required keys or values were invalid
1182          */
1183         @NonNull
1184         @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
build()1185         public Ikev2VpnProfile build() {
1186             return new Ikev2VpnProfile(
1187                     mType,
1188                     mServerAddr,
1189                     mUserIdentity,
1190                     mPresharedKey,
1191                     mServerRootCaCert,
1192                     mUsername,
1193                     mPassword,
1194                     mRsaPrivateKey,
1195                     mUserCert,
1196                     mProxyInfo,
1197                     mAllowedAlgorithms,
1198                     mIsBypassable,
1199                     mIsMetered,
1200                     mMaxMtu,
1201                     mIsRestrictedToTestNetworks,
1202                     mExcludeLocalRoutes,
1203                     mRequiresInternetValidation,
1204                     mIkeTunConnParams,
1205                     mAutomaticNattKeepaliveTimerEnabled,
1206                     mAutomaticIpVersionSelectionEnabled);
1207         }
1208     }
1209 }
1210