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.ipsec.ike; 18 19 import static android.system.OsConstants.AF_INET; 20 import static android.system.OsConstants.AF_INET6; 21 22 import android.annotation.IntDef; 23 import android.annotation.IntRange; 24 import android.annotation.NonNull; 25 import android.annotation.Nullable; 26 import android.annotation.SuppressLint; 27 import android.annotation.SystemApi; 28 import android.content.Context; 29 import android.net.ConnectivityManager; 30 import android.net.Network; 31 import android.net.eap.EapSessionConfig; 32 33 import com.android.internal.annotations.VisibleForTesting; 34 import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv4Pcscf; 35 import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv6Pcscf; 36 import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.IkeConfigAttribute; 37 import com.android.internal.net.ipsec.ike.message.IkePayload; 38 39 import java.lang.annotation.Retention; 40 import java.lang.annotation.RetentionPolicy; 41 import java.net.Inet4Address; 42 import java.net.Inet6Address; 43 import java.net.InetAddress; 44 import java.security.PrivateKey; 45 import java.security.cert.TrustAnchor; 46 import java.security.cert.X509Certificate; 47 import java.security.interfaces.RSAPrivateKey; 48 import java.util.ArrayList; 49 import java.util.Arrays; 50 import java.util.Collections; 51 import java.util.LinkedList; 52 import java.util.List; 53 import java.util.Objects; 54 import java.util.concurrent.TimeUnit; 55 56 /** 57 * IkeSessionParams contains all user provided configurations for negotiating an {@link IkeSession}. 58 * 59 * <p>Note that all negotiated configurations will be reused during rekey including SA Proposal and 60 * lifetime. 61 * 62 * @hide 63 */ 64 @SystemApi 65 public final class IkeSessionParams { 66 /** @hide */ 67 @Retention(RetentionPolicy.SOURCE) 68 @IntDef({IKE_AUTH_METHOD_PSK, IKE_AUTH_METHOD_PUB_KEY_SIGNATURE, IKE_AUTH_METHOD_EAP}) 69 public @interface IkeAuthMethod {} 70 71 // Constants to describe user configured authentication methods. 72 /** @hide */ 73 public static final int IKE_AUTH_METHOD_PSK = 1; 74 /** @hide */ 75 public static final int IKE_AUTH_METHOD_PUB_KEY_SIGNATURE = 2; 76 /** @hide */ 77 public static final int IKE_AUTH_METHOD_EAP = 3; 78 79 /** @hide */ 80 @Retention(RetentionPolicy.SOURCE) 81 @IntDef({IKE_OPTION_ACCEPT_ANY_REMOTE_ID, IKE_OPTION_EAP_ONLY_AUTH}) 82 public @interface IkeOption {} 83 84 /** 85 * If set, the IKE library will accept any remote (server) identity, even if it does not match 86 * the configured remote identity 87 * 88 * <p>See {@link Builder#setRemoteIdentification(IkeIdentification)} 89 */ 90 public static final int IKE_OPTION_ACCEPT_ANY_REMOTE_ID = 0; 91 /** 92 * If set, and EAP has been configured as the authentication method, the IKE library will 93 * request that the remote (also) use an EAP-only authentication flow. 94 * 95 * <p>@see {@link Builder#setAuthEap(X509Certificate, EapSessionConfig)} 96 */ 97 public static final int IKE_OPTION_EAP_ONLY_AUTH = 1; 98 99 private static final int MIN_IKE_OPTION = IKE_OPTION_ACCEPT_ANY_REMOTE_ID; 100 private static final int MAX_IKE_OPTION = IKE_OPTION_EAP_ONLY_AUTH; 101 102 /** @hide */ 103 @VisibleForTesting static final int IKE_HARD_LIFETIME_SEC_MINIMUM = 300; // 5 minutes 104 /** @hide */ 105 @VisibleForTesting static final int IKE_HARD_LIFETIME_SEC_MAXIMUM = 86400; // 24 hours 106 /** @hide */ 107 @VisibleForTesting static final int IKE_HARD_LIFETIME_SEC_DEFAULT = 14400; // 4 hours 108 109 /** @hide */ 110 @VisibleForTesting static final int IKE_SOFT_LIFETIME_SEC_MINIMUM = 120; // 2 minutes 111 /** @hide */ 112 @VisibleForTesting static final int IKE_SOFT_LIFETIME_SEC_DEFAULT = 7200; // 2 hours 113 114 /** @hide */ 115 @VisibleForTesting 116 static final int IKE_LIFETIME_MARGIN_SEC_MINIMUM = (int) TimeUnit.MINUTES.toSeconds(1L); 117 118 /** @hide */ 119 @VisibleForTesting static final int IKE_DPD_DELAY_SEC_MIN = 20; 120 /** @hide */ 121 @VisibleForTesting static final int IKE_DPD_DELAY_SEC_MAX = 1800; // 30 minutes 122 /** @hide */ 123 @VisibleForTesting static final int IKE_DPD_DELAY_SEC_DEFAULT = 120; // 2 minutes 124 125 /** @hide */ 126 @VisibleForTesting static final int IKE_RETRANS_TIMEOUT_MS_MIN = 500; 127 /** @hide */ 128 @VisibleForTesting 129 static final int IKE_RETRANS_TIMEOUT_MS_MAX = (int) TimeUnit.MINUTES.toMillis(30L); 130 /** @hide */ 131 @VisibleForTesting static final int IKE_RETRANS_MAX_ATTEMPTS_MAX = 10; 132 /** @hide */ 133 @VisibleForTesting 134 static final int[] IKE_RETRANS_TIMEOUT_MS_LIST_DEFAULT = 135 new int[] {500, 1000, 2000, 4000, 8000}; 136 137 @NonNull private final String mServerHostname; 138 @NonNull private final Network mNetwork; 139 140 @NonNull private final IkeSaProposal[] mSaProposals; 141 142 @NonNull private final IkeIdentification mLocalIdentification; 143 @NonNull private final IkeIdentification mRemoteIdentification; 144 145 @NonNull private final IkeAuthConfig mLocalAuthConfig; 146 @NonNull private final IkeAuthConfig mRemoteAuthConfig; 147 148 @NonNull private final IkeConfigAttribute[] mConfigRequests; 149 150 @NonNull private final int[] mRetransTimeoutMsList; 151 152 private final long mIkeOptions; 153 154 private final int mHardLifetimeSec; 155 private final int mSoftLifetimeSec; 156 157 private final int mDpdDelaySec; 158 159 private final boolean mIsIkeFragmentationSupported; 160 IkeSessionParams( @onNull String serverHostname, @NonNull Network network, @NonNull IkeSaProposal[] proposals, @NonNull IkeIdentification localIdentification, @NonNull IkeIdentification remoteIdentification, @NonNull IkeAuthConfig localAuthConfig, @NonNull IkeAuthConfig remoteAuthConfig, @NonNull IkeConfigAttribute[] configRequests, @NonNull int[] retransTimeoutMsList, long ikeOptions, int hardLifetimeSec, int softLifetimeSec, int dpdDelaySec, boolean isIkeFragmentationSupported)161 private IkeSessionParams( 162 @NonNull String serverHostname, 163 @NonNull Network network, 164 @NonNull IkeSaProposal[] proposals, 165 @NonNull IkeIdentification localIdentification, 166 @NonNull IkeIdentification remoteIdentification, 167 @NonNull IkeAuthConfig localAuthConfig, 168 @NonNull IkeAuthConfig remoteAuthConfig, 169 @NonNull IkeConfigAttribute[] configRequests, 170 @NonNull int[] retransTimeoutMsList, 171 long ikeOptions, 172 int hardLifetimeSec, 173 int softLifetimeSec, 174 int dpdDelaySec, 175 boolean isIkeFragmentationSupported) { 176 mServerHostname = serverHostname; 177 mNetwork = network; 178 179 mSaProposals = proposals; 180 181 mLocalIdentification = localIdentification; 182 mRemoteIdentification = remoteIdentification; 183 184 mLocalAuthConfig = localAuthConfig; 185 mRemoteAuthConfig = remoteAuthConfig; 186 187 mConfigRequests = configRequests; 188 189 mRetransTimeoutMsList = retransTimeoutMsList; 190 191 mIkeOptions = ikeOptions; 192 193 mHardLifetimeSec = hardLifetimeSec; 194 mSoftLifetimeSec = softLifetimeSec; 195 196 mDpdDelaySec = dpdDelaySec; 197 198 mIsIkeFragmentationSupported = isIkeFragmentationSupported; 199 } 200 validateIkeOptionOrThrow(@keOption int ikeOption)201 private static void validateIkeOptionOrThrow(@IkeOption int ikeOption) { 202 if (ikeOption < MIN_IKE_OPTION || ikeOption > MAX_IKE_OPTION) { 203 throw new IllegalArgumentException("Invalid IKE Option: " + ikeOption); 204 } 205 } 206 getOptionBitValue(int ikeOption)207 private static long getOptionBitValue(int ikeOption) { 208 return 1 << ikeOption; 209 } 210 211 /** 212 * Retrieves the configured server hostname 213 * 214 * <p>The configured server hostname will be resolved during IKE Session creation. 215 */ 216 @NonNull getServerHostname()217 public String getServerHostname() { 218 return mServerHostname; 219 } 220 221 /** Retrieves the configured {@link Network} */ 222 @NonNull getNetwork()223 public Network getNetwork() { 224 return mNetwork; 225 } 226 227 /** Retrieves all ChildSaProposals configured */ 228 @NonNull getSaProposals()229 public List<IkeSaProposal> getSaProposals() { 230 return Arrays.asList(mSaProposals); 231 } 232 233 /** @hide */ getSaProposalsInternal()234 public IkeSaProposal[] getSaProposalsInternal() { 235 return mSaProposals; 236 } 237 238 /** Retrieves the local (client) identity */ 239 @NonNull getLocalIdentification()240 public IkeIdentification getLocalIdentification() { 241 return mLocalIdentification; 242 } 243 244 /** Retrieves the required remote (server) identity */ 245 @NonNull getRemoteIdentification()246 public IkeIdentification getRemoteIdentification() { 247 return mRemoteIdentification; 248 } 249 250 /** Retrieves the local (client) authentication configuration */ 251 @NonNull getLocalAuthConfig()252 public IkeAuthConfig getLocalAuthConfig() { 253 return mLocalAuthConfig; 254 } 255 256 /** Retrieves the remote (server) authentication configuration */ 257 @NonNull getRemoteAuthConfig()258 public IkeAuthConfig getRemoteAuthConfig() { 259 return mRemoteAuthConfig; 260 } 261 262 /** Retrieves hard lifetime in seconds */ 263 // Use "second" because smaller unit won't make sense to describe a rekey interval. 264 @SuppressLint("MethodNameUnits") 265 @IntRange(from = IKE_HARD_LIFETIME_SEC_MINIMUM, to = IKE_HARD_LIFETIME_SEC_MAXIMUM) getHardLifetimeSeconds()266 public int getHardLifetimeSeconds() { 267 return mHardLifetimeSec; 268 } 269 270 /** Retrieves soft lifetime in seconds */ 271 // Use "second" because smaller unit does not make sense to a rekey interval. 272 @SuppressLint("MethodNameUnits") 273 @IntRange(from = IKE_SOFT_LIFETIME_SEC_MINIMUM, to = IKE_HARD_LIFETIME_SEC_MAXIMUM) getSoftLifetimeSeconds()274 public int getSoftLifetimeSeconds() { 275 return mSoftLifetimeSec; 276 } 277 278 /** Retrieves the Dead Peer Detection(DPD) delay in seconds */ 279 @IntRange(from = IKE_DPD_DELAY_SEC_MIN, to = IKE_DPD_DELAY_SEC_MAX) getDpdDelaySeconds()280 public int getDpdDelaySeconds() { 281 return mDpdDelaySec; 282 } 283 284 /** 285 * Retrieves the relative retransmission timeout list in milliseconds 286 * 287 * <p>@see {@link Builder#setRetransmissionTimeoutsMillis(int[])} 288 */ getRetransmissionTimeoutsMillis()289 public int[] getRetransmissionTimeoutsMillis() { 290 return mRetransTimeoutMsList; 291 } 292 293 /** Checks if the given IKE Session negotiation option is set */ hasIkeOption(@keOption int ikeOption)294 public boolean hasIkeOption(@IkeOption int ikeOption) { 295 validateIkeOptionOrThrow(ikeOption); 296 return (mIkeOptions & getOptionBitValue(ikeOption)) != 0; 297 } 298 299 /** @hide */ getHardLifetimeMsInternal()300 public long getHardLifetimeMsInternal() { 301 return TimeUnit.SECONDS.toMillis((long) mHardLifetimeSec); 302 } 303 304 /** @hide */ getSoftLifetimeMsInternal()305 public long getSoftLifetimeMsInternal() { 306 return TimeUnit.SECONDS.toMillis((long) mSoftLifetimeSec); 307 } 308 309 /** @hide */ isIkeFragmentationSupported()310 public boolean isIkeFragmentationSupported() { 311 return mIsIkeFragmentationSupported; 312 } 313 314 /** @hide */ getConfigurationAttributesInternal()315 public IkeConfigAttribute[] getConfigurationAttributesInternal() { 316 return mConfigRequests; 317 } 318 319 /** Retrieves the list of Configuration Requests */ 320 @NonNull getConfigurationRequests()321 public List<IkeConfigRequest> getConfigurationRequests() { 322 return Collections.unmodifiableList(Arrays.asList(mConfigRequests)); 323 } 324 325 /** Represents an IKE session configuration request type */ 326 public interface IkeConfigRequest {} 327 328 /** Represents an IPv4 P_CSCF request */ 329 public interface ConfigRequestIpv4PcscfServer extends IkeConfigRequest { 330 /** 331 * Retrieves the requested IPv4 P_CSCF server address 332 * 333 * @return The requested P_CSCF server address, or null if no specific P_CSCF server was 334 * requested 335 */ 336 @Nullable getAddress()337 Inet4Address getAddress(); 338 } 339 340 /** Represents an IPv6 P_CSCF request */ 341 public interface ConfigRequestIpv6PcscfServer extends IkeConfigRequest { 342 /** 343 * Retrieves the requested IPv6 P_CSCF server address 344 * 345 * @return The requested P_CSCF server address, or null if no specific P_CSCF server was 346 * requested 347 */ 348 @Nullable getAddress()349 Inet6Address getAddress(); 350 } 351 352 /** This class contains common information of an IKEv2 authentication configuration. */ 353 public abstract static class IkeAuthConfig { 354 /** @hide */ 355 @IkeAuthMethod public final int mAuthMethod; 356 357 /** @hide */ IkeAuthConfig(@keAuthMethod int authMethod)358 IkeAuthConfig(@IkeAuthMethod int authMethod) { 359 mAuthMethod = authMethod; 360 } 361 } 362 363 /** 364 * This class represents the configuration to support IKEv2 pre-shared-key-based authentication 365 * of local or remote side. 366 */ 367 public static class IkeAuthPskConfig extends IkeAuthConfig { 368 /** @hide */ 369 @NonNull public final byte[] mPsk; 370 IkeAuthPskConfig(byte[] psk)371 private IkeAuthPskConfig(byte[] psk) { 372 super(IKE_AUTH_METHOD_PSK); 373 mPsk = psk; 374 } 375 376 /** Retrieves the pre-shared key */ 377 @NonNull getPsk()378 public byte[] getPsk() { 379 return Arrays.copyOf(mPsk, mPsk.length); 380 } 381 } 382 383 /** 384 * This class represents the configuration to support IKEv2 public-key-signature-based 385 * authentication of the remote side. 386 */ 387 public static class IkeAuthDigitalSignRemoteConfig extends IkeAuthConfig { 388 /** @hide */ 389 @Nullable public final TrustAnchor mTrustAnchor; 390 391 /** 392 * If a certificate is provided, it MUST be the root CA used by the remote (server), or 393 * authentication will fail. If no certificate is provided, any root CA in the system's 394 * truststore is considered acceptable. 395 */ IkeAuthDigitalSignRemoteConfig(@ullable X509Certificate caCert)396 private IkeAuthDigitalSignRemoteConfig(@Nullable X509Certificate caCert) { 397 super(IKE_AUTH_METHOD_PUB_KEY_SIGNATURE); 398 if (caCert == null) { 399 mTrustAnchor = null; 400 } else { 401 // The name constraints extension, defined in RFC 5280, indicates a name space 402 // within which all subject names in subsequent certificates in a certification path 403 // MUST be located. 404 mTrustAnchor = new TrustAnchor(caCert, null /*nameConstraints*/); 405 406 // TODO: Investigate if we need to support the name constraints extension. 407 } 408 } 409 410 /** Retrieves the provided CA certificate for validating the remote certificate(s) */ 411 @Nullable getRemoteCaCert()412 public X509Certificate getRemoteCaCert() { 413 if (mTrustAnchor == null) return null; 414 return mTrustAnchor.getTrustedCert(); 415 } 416 } 417 418 /** 419 * This class represents the configuration to support IKEv2 public-key-signature-based 420 * authentication of the local side. 421 */ 422 public static class IkeAuthDigitalSignLocalConfig extends IkeAuthConfig { 423 /** @hide */ 424 @NonNull public final X509Certificate mEndCert; 425 426 /** @hide */ 427 @NonNull public final List<X509Certificate> mIntermediateCerts; 428 429 /** @hide */ 430 @NonNull public final PrivateKey mPrivateKey; 431 IkeAuthDigitalSignLocalConfig( @onNull X509Certificate clientEndCert, @NonNull List<X509Certificate> clientIntermediateCerts, @NonNull PrivateKey privateKey)432 private IkeAuthDigitalSignLocalConfig( 433 @NonNull X509Certificate clientEndCert, 434 @NonNull List<X509Certificate> clientIntermediateCerts, 435 @NonNull PrivateKey privateKey) { 436 super(IKE_AUTH_METHOD_PUB_KEY_SIGNATURE); 437 mEndCert = clientEndCert; 438 mIntermediateCerts = clientIntermediateCerts; 439 mPrivateKey = privateKey; 440 } 441 442 /** Retrieves the client end certificate */ 443 @NonNull getClientEndCertificate()444 public X509Certificate getClientEndCertificate() { 445 return mEndCert; 446 } 447 448 /** Retrieves the intermediate certificates */ 449 @NonNull getIntermediateCertificates()450 public List<X509Certificate> getIntermediateCertificates() { 451 return mIntermediateCerts; 452 } 453 454 /** Retrieves the private key */ 455 @NonNull getPrivateKey()456 public PrivateKey getPrivateKey() { 457 return mPrivateKey; 458 } 459 } 460 461 /** 462 * This class represents the configuration to support EAP authentication of the local side. 463 * 464 * <p>@see {@link IkeSessionParams.Builder#setAuthEap(X509Certificate, EapSessionConfig)} 465 */ 466 public static class IkeAuthEapConfig extends IkeAuthConfig { 467 /** @hide */ 468 @NonNull public final EapSessionConfig mEapConfig; 469 IkeAuthEapConfig(EapSessionConfig eapConfig)470 private IkeAuthEapConfig(EapSessionConfig eapConfig) { 471 super(IKE_AUTH_METHOD_EAP); 472 473 mEapConfig = eapConfig; 474 } 475 476 /** Retrieves EAP configuration */ 477 @NonNull getEapConfig()478 public EapSessionConfig getEapConfig() { 479 return mEapConfig; 480 } 481 } 482 483 /** This class can be used to incrementally construct a {@link IkeSessionParams}. */ 484 public static final class Builder { 485 @NonNull private final ConnectivityManager mConnectivityManager; 486 487 @NonNull private final List<IkeSaProposal> mSaProposalList = new LinkedList<>(); 488 @NonNull private final List<IkeConfigAttribute> mConfigRequestList = new ArrayList<>(); 489 490 @NonNull 491 private int[] mRetransTimeoutMsList = 492 Arrays.copyOf( 493 IKE_RETRANS_TIMEOUT_MS_LIST_DEFAULT, 494 IKE_RETRANS_TIMEOUT_MS_LIST_DEFAULT.length); 495 496 @NonNull private String mServerHostname; 497 @Nullable private Network mNetwork; 498 499 @Nullable private IkeIdentification mLocalIdentification; 500 @Nullable private IkeIdentification mRemoteIdentification; 501 502 @Nullable private IkeAuthConfig mLocalAuthConfig; 503 @Nullable private IkeAuthConfig mRemoteAuthConfig; 504 505 private long mIkeOptions = 0; 506 507 private int mHardLifetimeSec = IKE_HARD_LIFETIME_SEC_DEFAULT; 508 private int mSoftLifetimeSec = IKE_SOFT_LIFETIME_SEC_DEFAULT; 509 510 private int mDpdDelaySec = IKE_DPD_DELAY_SEC_DEFAULT; 511 512 private boolean mIsIkeFragmentationSupported = false; 513 514 /** 515 * Construct Builder 516 * 517 * @param context a valid {@link Context} instance. 518 */ Builder(@onNull Context context)519 public Builder(@NonNull Context context) { 520 this((ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE)); 521 } 522 523 /** @hide */ 524 @VisibleForTesting Builder(ConnectivityManager connectManager)525 public Builder(ConnectivityManager connectManager) { 526 mConnectivityManager = connectManager; 527 } 528 529 /** 530 * Sets the server hostname for the {@link IkeSessionParams} being built. 531 * 532 * @param serverHostname the hostname of the IKE server, such as "ike.android.com". 533 * @return Builder this, to facilitate chaining. 534 */ 535 @NonNull setServerHostname(@onNull String serverHostname)536 public Builder setServerHostname(@NonNull String serverHostname) { 537 Objects.requireNonNull(serverHostname, "Required argument not provided"); 538 539 mServerHostname = serverHostname; 540 return this; 541 } 542 543 /** 544 * Sets the {@link Network} for the {@link IkeSessionParams} being built. 545 * 546 * <p>If no {@link Network} is provided, the default Network (as per {@link 547 * ConnectivityManager#getActiveNetwork()}) will be used. 548 * 549 * @param network the {@link Network} that IKE Session will use. 550 * @return Builder this, to facilitate chaining. 551 */ 552 @NonNull setNetwork(@onNull Network network)553 public Builder setNetwork(@NonNull Network network) { 554 if (network == null) { 555 throw new NullPointerException("Required argument not provided"); 556 } 557 558 mNetwork = network; 559 return this; 560 } 561 562 /** 563 * Sets local IKE identification for the {@link IkeSessionParams} being built. 564 * 565 * <p>It is not allowed to use KEY ID together with digital-signature-based authentication 566 * as per RFC 7296. 567 * 568 * @param identification the local IKE identification. 569 * @return Builder this, to facilitate chaining. 570 */ 571 @NonNull setLocalIdentification(@onNull IkeIdentification identification)572 public Builder setLocalIdentification(@NonNull IkeIdentification identification) { 573 if (identification == null) { 574 throw new NullPointerException("Required argument not provided"); 575 } 576 577 mLocalIdentification = identification; 578 return this; 579 } 580 581 /** 582 * Sets remote IKE identification for the {@link IkeSessionParams} being built. 583 * 584 * @param identification the remote IKE identification. 585 * @return Builder this, to facilitate chaining. 586 */ 587 @NonNull setRemoteIdentification(@onNull IkeIdentification identification)588 public Builder setRemoteIdentification(@NonNull IkeIdentification identification) { 589 if (identification == null) { 590 throw new NullPointerException("Required argument not provided"); 591 } 592 593 mRemoteIdentification = identification; 594 return this; 595 } 596 597 /** 598 * Adds an IKE SA proposal to the {@link IkeSessionParams} being built. 599 * 600 * @param proposal IKE SA proposal. 601 * @return Builder this, to facilitate chaining. 602 */ 603 @NonNull addSaProposal(@onNull IkeSaProposal proposal)604 public Builder addSaProposal(@NonNull IkeSaProposal proposal) { 605 if (proposal == null) { 606 throw new NullPointerException("Required argument not provided"); 607 } 608 609 if (proposal.getProtocolId() != IkePayload.PROTOCOL_ID_IKE) { 610 throw new IllegalArgumentException( 611 "Expected IKE SA Proposal but received Child SA proposal"); 612 } 613 mSaProposalList.add(proposal); 614 return this; 615 } 616 617 /** 618 * Configures the {@link IkeSession} to use pre-shared-key-based authentication. 619 * 620 * <p>Both client and server MUST be authenticated using the provided shared key. IKE 621 * authentication will fail if the remote peer tries to use other authentication methods. 622 * 623 * <p>Callers MUST declare only one authentication method. Calling this function will 624 * override the previously set authentication configuration. 625 * 626 * <p>Callers SHOULD NOT use this if any other authentication methods can be used; PSK-based 627 * authentication is generally considered insecure. 628 * 629 * @param sharedKey the shared key. 630 * @return Builder this, to facilitate chaining. 631 */ 632 @NonNull setAuthPsk(@onNull byte[] sharedKey)633 public Builder setAuthPsk(@NonNull byte[] sharedKey) { 634 if (sharedKey == null) { 635 throw new NullPointerException("Required argument not provided"); 636 } 637 638 mLocalAuthConfig = new IkeAuthPskConfig(sharedKey); 639 mRemoteAuthConfig = new IkeAuthPskConfig(sharedKey); 640 return this; 641 } 642 643 /** 644 * Configures the {@link IkeSession} to use EAP authentication. 645 * 646 * <p>Not all EAP methods provide mutual authentication. As such EAP MUST be used in 647 * conjunction with a public-key-signature-based authentication of the remote server, unless 648 * EAP-Only authentication is enabled. 649 * 650 * <p>Callers may enable EAP-Only authentication by setting {@link 651 * IKE_OPTION_EAP_ONLY_AUTH}, which will make IKE library request the remote to use EAP-Only 652 * authentication. The remote may opt to reject the request, at which point the received 653 * certificates and authentication payload WILL be validated with the provided root CA or 654 * system's truststore as usual. Only safe EAP methods as listed in RFC 5998 will be 655 * accepted for EAP-Only authentication. 656 * 657 * <p>If {@link IKE_OPTION_EAP_ONLY_AUTH} is set, callers MUST configure EAP as the 658 * authentication method and all EAP methods set in EAP Session configuration MUST be safe 659 * methods that are accepted for EAP-Only authentication. Otherwise callers will get an 660 * exception when building the {@link IkeSessionParams} 661 * 662 * <p>Callers MUST declare only one authentication method. Calling this function will 663 * override the previously set authentication configuration. 664 * 665 * @see <a href="https://tools.ietf.org/html/rfc5280">RFC 5280, Internet X.509 Public Key 666 * Infrastructure Certificate and Certificate Revocation List (CRL) Profile</a> 667 * @see <a href="https://tools.ietf.org/html/rfc5998">RFC 5998, An Extension for EAP-Only 668 * Authentication in IKEv2 669 * @param serverCaCert the CA certificate for validating the received server certificate(s). 670 * If a certificate is provided, it MUST be the root CA used by the server, or 671 * authentication will fail. If no certificate is provided, any root CA in the system's 672 * truststore is considered acceptable. 673 * @return Builder this, to facilitate chaining. 674 */ 675 // TODO(b/151667921): Consider also supporting configuring EAP method that is not accepted 676 // by EAP-Only when {@link IKE_OPTION_EAP_ONLY_AUTH} is set 677 @NonNull setAuthEap( @ullable X509Certificate serverCaCert, @NonNull EapSessionConfig eapConfig)678 public Builder setAuthEap( 679 @Nullable X509Certificate serverCaCert, @NonNull EapSessionConfig eapConfig) { 680 if (eapConfig == null) { 681 throw new NullPointerException("Required argument not provided"); 682 } 683 684 mLocalAuthConfig = new IkeAuthEapConfig(eapConfig); 685 mRemoteAuthConfig = new IkeAuthDigitalSignRemoteConfig(serverCaCert); 686 687 return this; 688 } 689 690 /** 691 * Configures the {@link IkeSession} to use public-key-signature-based authentication. 692 * 693 * <p>The public key included by the client end certificate and the private key used for 694 * signing MUST be a matching key pair. 695 * 696 * <p>The IKE library will use the strongest signature algorithm supported by both sides. 697 * 698 * <p>Currenly only RSA digital signature is supported. 699 * 700 * @param serverCaCert the CA certificate for validating the received server certificate(s). 701 * If a certificate is provided, it MUST be the root CA used by the server, or 702 * authentication will fail. If no certificate is provided, any root CA in the system's 703 * truststore is considered acceptable. 704 * @param clientEndCert the end certificate for remote server to verify the locally 705 * generated signature. 706 * @param clientPrivateKey private key to generate outbound digital signature. Only {@link 707 * RSAPrivateKey} is supported. 708 * @return Builder this, to facilitate chaining. 709 */ 710 @NonNull setAuthDigitalSignature( @ullable X509Certificate serverCaCert, @NonNull X509Certificate clientEndCert, @NonNull PrivateKey clientPrivateKey)711 public Builder setAuthDigitalSignature( 712 @Nullable X509Certificate serverCaCert, 713 @NonNull X509Certificate clientEndCert, 714 @NonNull PrivateKey clientPrivateKey) { 715 return setAuthDigitalSignature( 716 serverCaCert, 717 clientEndCert, 718 new LinkedList<X509Certificate>(), 719 clientPrivateKey); 720 } 721 722 /** 723 * Configures the {@link IkeSession} to use public-key-signature-based authentication. 724 * 725 * <p>The public key included by the client end certificate and the private key used for 726 * signing MUST be a matching key pair. 727 * 728 * <p>The IKE library will use the strongest signature algorithm supported by both sides. 729 * 730 * <p>Currenly only RSA digital signature is supported. 731 * 732 * @param serverCaCert the CA certificate for validating the received server certificate(s). 733 * If a null value is provided, IKE library will try all default CA certificates stored 734 * in Android system to do the validation. Otherwise, it will only use the provided CA 735 * certificate. 736 * @param clientEndCert the end certificate for remote server to verify locally generated 737 * signature. 738 * @param clientIntermediateCerts intermediate certificates for the remote server to 739 * validate the end certificate. 740 * @param clientPrivateKey private key to generate outbound digital signature. Only {@link 741 * RSAPrivateKey} is supported. 742 * @return Builder this, to facilitate chaining. 743 */ 744 @NonNull setAuthDigitalSignature( @ullable X509Certificate serverCaCert, @NonNull X509Certificate clientEndCert, @NonNull List<X509Certificate> clientIntermediateCerts, @NonNull PrivateKey clientPrivateKey)745 public Builder setAuthDigitalSignature( 746 @Nullable X509Certificate serverCaCert, 747 @NonNull X509Certificate clientEndCert, 748 @NonNull List<X509Certificate> clientIntermediateCerts, 749 @NonNull PrivateKey clientPrivateKey) { 750 if (clientEndCert == null 751 || clientIntermediateCerts == null 752 || clientPrivateKey == null) { 753 throw new NullPointerException("Required argument not provided"); 754 } 755 756 if (!(clientPrivateKey instanceof RSAPrivateKey)) { 757 throw new IllegalArgumentException("Unsupported private key type"); 758 } 759 760 mLocalAuthConfig = 761 new IkeAuthDigitalSignLocalConfig( 762 clientEndCert, clientIntermediateCerts, clientPrivateKey); 763 mRemoteAuthConfig = new IkeAuthDigitalSignRemoteConfig(serverCaCert); 764 765 return this; 766 } 767 768 /** 769 * Adds a specific internal P_CSCF server request to the {@link IkeSessionParams} being 770 * built. 771 * 772 * @param address the requested P_CSCF address. 773 * @return Builder this, to facilitate chaining. 774 */ 775 @NonNull addPcscfServerRequest(@onNull InetAddress address)776 public Builder addPcscfServerRequest(@NonNull InetAddress address) { 777 if (address == null) { 778 throw new NullPointerException("Required argument not provided"); 779 } 780 781 if (address instanceof Inet4Address) { 782 mConfigRequestList.add(new ConfigAttributeIpv4Pcscf((Inet4Address) address)); 783 } else if (address instanceof Inet6Address) { 784 mConfigRequestList.add(new ConfigAttributeIpv6Pcscf((Inet6Address) address)); 785 } else { 786 throw new IllegalArgumentException("Invalid address family"); 787 } 788 return this; 789 } 790 791 /** 792 * Adds a internal P_CSCF server request to the {@link IkeSessionParams} being built. 793 * 794 * @param addressFamily the address family. Only {@link OsConstants.AF_INET} and {@link 795 * OsConstants.AF_INET6} are allowed. 796 * @return Builder this, to facilitate chaining. 797 */ 798 @NonNull addPcscfServerRequest(int addressFamily)799 public Builder addPcscfServerRequest(int addressFamily) { 800 if (addressFamily == AF_INET) { 801 mConfigRequestList.add(new ConfigAttributeIpv4Pcscf()); 802 return this; 803 } else if (addressFamily == AF_INET6) { 804 mConfigRequestList.add(new ConfigAttributeIpv6Pcscf()); 805 return this; 806 } else { 807 throw new IllegalArgumentException("Invalid address family: " + addressFamily); 808 } 809 } 810 811 /** 812 * Sets hard and soft lifetimes. 813 * 814 * <p>Lifetimes will not be negotiated with the remote IKE server. 815 * 816 * @param hardLifetimeSeconds number of seconds after which IKE SA will expire. Defaults to 817 * 14400 seconds (4 hours). MUST be a value from 300 seconds (5 minutes) to 86400 818 * seconds (24 hours), inclusive. 819 * @param softLifetimeSeconds number of seconds after which IKE SA will request rekey. 820 * Defaults to 7200 seconds (2 hours). MUST be at least 120 seconds (2 minutes), and at 821 * least 60 seconds (1 minute) shorter than the hard lifetime. 822 * @return Builder this, to facilitate chaining. 823 */ 824 @NonNull setLifetimeSeconds( @ntRangefrom = IKE_HARD_LIFETIME_SEC_MINIMUM, to = IKE_HARD_LIFETIME_SEC_MAXIMUM) int hardLifetimeSeconds, @IntRange(from = IKE_SOFT_LIFETIME_SEC_MINIMUM, to = IKE_HARD_LIFETIME_SEC_MAXIMUM) int softLifetimeSeconds)825 public Builder setLifetimeSeconds( 826 @IntRange(from = IKE_HARD_LIFETIME_SEC_MINIMUM, to = IKE_HARD_LIFETIME_SEC_MAXIMUM) 827 int hardLifetimeSeconds, 828 @IntRange(from = IKE_SOFT_LIFETIME_SEC_MINIMUM, to = IKE_HARD_LIFETIME_SEC_MAXIMUM) 829 int softLifetimeSeconds) { 830 if (hardLifetimeSeconds < IKE_HARD_LIFETIME_SEC_MINIMUM 831 || hardLifetimeSeconds > IKE_HARD_LIFETIME_SEC_MAXIMUM 832 || softLifetimeSeconds < IKE_SOFT_LIFETIME_SEC_MINIMUM 833 || hardLifetimeSeconds - softLifetimeSeconds 834 < IKE_LIFETIME_MARGIN_SEC_MINIMUM) { 835 throw new IllegalArgumentException("Invalid lifetime value"); 836 } 837 838 mHardLifetimeSec = hardLifetimeSeconds; 839 mSoftLifetimeSec = softLifetimeSeconds; 840 return this; 841 } 842 843 /** 844 * Sets the Dead Peer Detection(DPD) delay in seconds. 845 * 846 * @param dpdDelaySeconds number of seconds after which IKE SA will initiate DPD if no 847 * inbound cryptographically protected IKE message was received. Defaults to 120 848 * seconds. MUST be a value from 20 seconds to 1800 seconds, inclusive. 849 * @return Builder this, to facilitate chaining. 850 */ 851 @NonNull setDpdDelaySeconds( @ntRangefrom = IKE_DPD_DELAY_SEC_MIN, to = IKE_DPD_DELAY_SEC_MAX) int dpdDelaySeconds)852 public Builder setDpdDelaySeconds( 853 @IntRange(from = IKE_DPD_DELAY_SEC_MIN, to = IKE_DPD_DELAY_SEC_MAX) 854 int dpdDelaySeconds) { 855 if (dpdDelaySeconds < IKE_DPD_DELAY_SEC_MIN 856 || dpdDelaySeconds > IKE_DPD_DELAY_SEC_MAX) { 857 throw new IllegalArgumentException("Invalid DPD delay value"); 858 } 859 mDpdDelaySec = dpdDelaySeconds; 860 return this; 861 } 862 863 /** 864 * Sets the retransmission timeout list in milliseconds. 865 * 866 * <p>Configures the retransmission by providing an array of relative retransmission 867 * timeouts in milliseconds, where each timeout is the waiting time before next retry, 868 * except the last timeout is the waiting time before terminating the IKE Session. Each 869 * element in the array MUST be a value from 500 ms to 1800000 ms (30 minutes). The length 870 * of the array MUST NOT exceed 10. This retransmission timeout list defaults to {0.5s, 1s, 871 * 2s, 4s, 8s} 872 * 873 * @param retransTimeoutMillisList the array of relative retransmission timeout in 874 * milliseconds. 875 * @return Builder this, to facilitate chaining. 876 */ 877 @NonNull setRetransmissionTimeoutsMillis(@onNull int[] retransTimeoutMillisList)878 public Builder setRetransmissionTimeoutsMillis(@NonNull int[] retransTimeoutMillisList) { 879 boolean isValid = true; 880 if (retransTimeoutMillisList == null 881 || retransTimeoutMillisList.length == 0 882 || retransTimeoutMillisList.length > IKE_RETRANS_MAX_ATTEMPTS_MAX) { 883 isValid = false; 884 } 885 for (int t : retransTimeoutMillisList) { 886 if (t < IKE_RETRANS_TIMEOUT_MS_MIN || t > IKE_RETRANS_TIMEOUT_MS_MAX) { 887 isValid = false; 888 } 889 } 890 if (!isValid) throw new IllegalArgumentException("Invalid retransmission timeout list"); 891 892 mRetransTimeoutMsList = retransTimeoutMillisList; 893 return this; 894 } 895 896 /** 897 * Sets the specified IKE Option as enabled. 898 * 899 * @param ikeOption the option to be enabled. 900 * @return Builder this, to facilitate chaining. 901 */ 902 @NonNull addIkeOption(@keOption int ikeOption)903 public Builder addIkeOption(@IkeOption int ikeOption) { 904 validateIkeOptionOrThrow(ikeOption); 905 mIkeOptions |= getOptionBitValue(ikeOption); 906 return this; 907 } 908 909 /** 910 * Resets (disables) the specified IKE Option. 911 * 912 * @param ikeOption the option to be disabled. 913 * @return Builder this, to facilitate chaining. 914 */ 915 @NonNull removeIkeOption(@keOption int ikeOption)916 public Builder removeIkeOption(@IkeOption int ikeOption) { 917 validateIkeOptionOrThrow(ikeOption); 918 mIkeOptions &= ~getOptionBitValue(ikeOption); 919 return this; 920 } 921 922 /** 923 * Validates and builds the {@link IkeSessionParams}. 924 * 925 * @return IkeSessionParams the validated IkeSessionParams. 926 */ 927 @NonNull build()928 public IkeSessionParams build() { 929 if (mSaProposalList.isEmpty()) { 930 throw new IllegalArgumentException("IKE SA proposal not found"); 931 } 932 933 Network network = mNetwork != null ? mNetwork : mConnectivityManager.getActiveNetwork(); 934 if (network == null) { 935 throw new IllegalArgumentException("Network not found"); 936 } 937 938 if (mServerHostname == null 939 || mLocalIdentification == null 940 || mRemoteIdentification == null 941 || mLocalAuthConfig == null 942 || mRemoteAuthConfig == null) { 943 throw new IllegalArgumentException("Necessary parameter missing."); 944 } 945 946 if ((mIkeOptions & getOptionBitValue(IKE_OPTION_EAP_ONLY_AUTH)) != 0) { 947 if (!(mLocalAuthConfig instanceof IkeAuthEapConfig)) { 948 throw new IllegalArgumentException( 949 "If IKE_OPTION_EAP_ONLY_AUTH is set," 950 + " eap authentication needs to be configured."); 951 } 952 953 IkeAuthEapConfig ikeAuthEapConfig = (IkeAuthEapConfig) mLocalAuthConfig; 954 if (!ikeAuthEapConfig.getEapConfig().areAllMethodsEapOnlySafe()) { 955 throw new IllegalArgumentException( 956 "Only EAP-only safe method allowed" + " when using EAP-only option."); 957 } 958 } 959 960 if (mLocalAuthConfig.mAuthMethod == IKE_AUTH_METHOD_PUB_KEY_SIGNATURE 961 && mLocalIdentification.idType == IkeIdentification.ID_TYPE_KEY_ID) { 962 throw new IllegalArgumentException( 963 "It is not allowed to use KEY_ID as local ID when local authentication" 964 + " method is digital-signature-based"); 965 } 966 967 return new IkeSessionParams( 968 mServerHostname, 969 network, 970 mSaProposalList.toArray(new IkeSaProposal[0]), 971 mLocalIdentification, 972 mRemoteIdentification, 973 mLocalAuthConfig, 974 mRemoteAuthConfig, 975 mConfigRequestList.toArray(new IkeConfigAttribute[0]), 976 mRetransTimeoutMsList, 977 mIkeOptions, 978 mHardLifetimeSec, 979 mSoftLifetimeSec, 980 mDpdDelaySec, 981 mIsIkeFragmentationSupported); 982 } 983 984 // TODO: add methods for supporting IKE fragmentation. 985 } 986 } 987