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