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