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.eap; 18 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.annotation.SystemApi; 23 import android.os.PersistableBundle; 24 import android.telephony.Annotation.UiccAppType; 25 26 import com.android.internal.annotations.VisibleForTesting; 27 import com.android.internal.net.ipsec.ike.utils.IkeCertUtils; 28 import com.android.server.vcn.util.PersistableBundleUtils; 29 30 import java.lang.annotation.Retention; 31 import java.lang.annotation.RetentionPolicy; 32 import java.security.cert.CertificateEncodingException; 33 import java.security.cert.TrustAnchor; 34 import java.security.cert.X509Certificate; 35 import java.util.Arrays; 36 import java.util.Collections; 37 import java.util.HashMap; 38 import java.util.Map; 39 import java.util.Objects; 40 41 /** 42 * EapSessionConfig represents a container for EAP method configuration. 43 * 44 * <p>The EAP authentication server decides which EAP method is used, so clients are encouraged to 45 * provide configs for several EAP methods. 46 */ 47 public final class EapSessionConfig { 48 private static final String EAP_ID_KEY = "eapIdentity"; 49 private static final String EAP_METHOD_CONFIGS_KEY = "eapConfigs"; 50 51 private static final byte[] DEFAULT_IDENTITY = new byte[0]; 52 53 // IANA -> EapMethodConfig for that method 54 private final Map<Integer, EapMethodConfig> mEapConfigs; 55 private final byte[] mEapIdentity; 56 57 /** @hide */ 58 @VisibleForTesting EapSessionConfig(Map<Integer, EapMethodConfig> eapConfigs, byte[] eapIdentity)59 public EapSessionConfig(Map<Integer, EapMethodConfig> eapConfigs, byte[] eapIdentity) { 60 Objects.requireNonNull(eapConfigs, "eapConfigs must not be null"); 61 Objects.requireNonNull(eapIdentity, "eapIdentity must not be null"); 62 63 mEapConfigs = Collections.unmodifiableMap(eapConfigs); 64 mEapIdentity = eapIdentity; 65 } 66 67 /** 68 * Gets the EAP configs set in this EapSessionConfig. 69 * 70 * @hide 71 */ getEapConfigs()72 public Map<Integer, EapMethodConfig> getEapConfigs() { 73 // Return the underlying Collection directly because it's unmodifiable 74 return mEapConfigs; 75 } 76 77 /** 78 * Constructs this object by deserializing a PersistableBundle * 79 * 80 * <p>Constructed EapSessionConfigs are guaranteed to be valid, as checked by the 81 * EapSessionConfig.Builder 82 * 83 * @hide 84 */ 85 @NonNull fromPersistableBundle(@onNull PersistableBundle in)86 public static EapSessionConfig fromPersistableBundle(@NonNull PersistableBundle in) { 87 Objects.requireNonNull(in, "PersistableBundle is null"); 88 89 EapSessionConfig.Builder builder = new EapSessionConfig.Builder(); 90 91 PersistableBundle eapIdBundle = in.getPersistableBundle(EAP_ID_KEY); 92 Objects.requireNonNull(eapIdBundle, "EAP ID bundle is null"); 93 byte[] eapId = PersistableBundleUtils.toByteArray(eapIdBundle); 94 builder.setEapIdentity(eapId); 95 96 PersistableBundle configsBundle = in.getPersistableBundle(EAP_METHOD_CONFIGS_KEY); 97 Objects.requireNonNull(configsBundle, "EAP method configs bundle is null"); 98 Map<Integer, EapMethodConfig> eapMethodConfigs = 99 PersistableBundleUtils.toMap( 100 configsBundle, 101 PersistableBundleUtils.INTEGER_DESERIALIZER, 102 EapMethodConfig::fromPersistableBundle); 103 for (EapMethodConfig config : eapMethodConfigs.values()) { 104 builder.addEapMethodConfig(config); 105 } 106 107 return builder.build(); 108 } 109 110 /** 111 * Serializes this object to a PersistableBundle 112 * 113 * @hide 114 */ 115 @NonNull toPersistableBundle()116 public PersistableBundle toPersistableBundle() { 117 final PersistableBundle result = new PersistableBundle(); 118 result.putPersistableBundle(EAP_ID_KEY, PersistableBundleUtils.fromByteArray(mEapIdentity)); 119 120 final PersistableBundle configsBundle = 121 PersistableBundleUtils.fromMap( 122 mEapConfigs, 123 PersistableBundleUtils.INTEGER_SERIALIZER, 124 EapMethodConfig::toPersistableBundle); 125 result.putPersistableBundle(EAP_METHOD_CONFIGS_KEY, configsBundle); 126 return result; 127 } 128 129 /** Retrieves client's EAP Identity */ 130 @NonNull getEapIdentity()131 public byte[] getEapIdentity() { 132 return mEapIdentity.clone(); 133 } 134 135 /** 136 * Retrieves configuration for EAP SIM 137 * 138 * @return the configuration for EAP SIM, or null if it was not set 139 */ 140 @Nullable getEapSimConfig()141 public EapSimConfig getEapSimConfig() { 142 return (EapSimConfig) mEapConfigs.get(EapMethodConfig.EAP_TYPE_SIM); 143 } 144 145 /** 146 * Retrieves configuration for EAP AKA 147 * 148 * @return the configuration for EAP AKA, or null if it was not set 149 */ 150 @Nullable getEapAkaConfig()151 public EapAkaConfig getEapAkaConfig() { 152 return (EapAkaConfig) mEapConfigs.get(EapMethodConfig.EAP_TYPE_AKA); 153 } 154 155 /** 156 * Retrieves configuration for EAP AKA' 157 * 158 * @return the configuration for EAP AKA', or null if it was not set 159 */ 160 @Nullable getEapAkaPrimeConfig()161 public EapAkaPrimeConfig getEapAkaPrimeConfig() { 162 return (EapAkaPrimeConfig) mEapConfigs.get(EapMethodConfig.EAP_TYPE_AKA_PRIME); 163 } 164 165 /** 166 * Retrieves configuration for EAP MSCHAPV2 167 * 168 * @return the configuration for EAP MSCHAPV2, or null if it was not set 169 */ 170 @Nullable getEapMsChapV2Config()171 public EapMsChapV2Config getEapMsChapV2Config() { 172 return (EapMsChapV2Config) mEapConfigs.get(EapMethodConfig.EAP_TYPE_MSCHAP_V2); 173 } 174 175 /** 176 * Retrieves configuration for EAP MSCHAPV2 177 * 178 * @return the configuration for EAP MSCHAPV2, or null if it was not set 179 * @hide 180 * @deprecated Callers should use {@link #getEapMsChapV2Config} 181 */ 182 @Deprecated 183 @SystemApi 184 @Nullable getEapMsChapV2onfig()185 public EapMsChapV2Config getEapMsChapV2onfig() { 186 return getEapMsChapV2Config(); 187 } 188 189 /** 190 * Retrieves configuration for EAP-TTLS 191 * 192 * @return the configuration for EAP-TTLS, or null if it was not set 193 */ 194 @Nullable getEapTtlsConfig()195 public EapTtlsConfig getEapTtlsConfig() { 196 return (EapTtlsConfig) mEapConfigs.get(EapMethodConfig.EAP_TYPE_TTLS); 197 } 198 199 /** @hide */ 200 @Override hashCode()201 public int hashCode() { 202 return Objects.hash(Arrays.hashCode(mEapIdentity), mEapConfigs); 203 } 204 205 /** @hide */ 206 @Override equals(Object o)207 public boolean equals(Object o) { 208 if (!(o instanceof EapSessionConfig)) { 209 return false; 210 } 211 212 EapSessionConfig other = (EapSessionConfig) o; 213 return Arrays.equals(mEapIdentity, other.mEapIdentity) 214 && mEapConfigs.equals(other.mEapConfigs); 215 } 216 217 /** This class can be used to incrementally construct an {@link EapSessionConfig}. */ 218 public static final class Builder { 219 private final Map<Integer, EapMethodConfig> mEapConfigs; 220 private byte[] mEapIdentity; 221 222 /** Constructs and returns a new Builder for constructing an {@link EapSessionConfig}. */ Builder()223 public Builder() { 224 mEapConfigs = new HashMap<>(); 225 mEapIdentity = DEFAULT_IDENTITY; 226 } 227 228 /** 229 * Sets the client's EAP Identity. 230 * 231 * @param eapIdentity byte[] representing the client's EAP Identity. 232 * @return Builder this, to facilitate chaining. 233 */ 234 @NonNull setEapIdentity(@onNull byte[] eapIdentity)235 public Builder setEapIdentity(@NonNull byte[] eapIdentity) { 236 Objects.requireNonNull(eapIdentity, "eapIdentity must not be null"); 237 this.mEapIdentity = eapIdentity.clone(); 238 return this; 239 } 240 241 /** 242 * Sets the configuration for EAP SIM. 243 * 244 * @param subId int the client's subId to be authenticated. 245 * @param apptype the {@link UiccAppType} apptype to be used for authentication. 246 * @return Builder this, to facilitate chaining. 247 */ 248 @NonNull setEapSimConfig(int subId, @UiccAppType int apptype)249 public Builder setEapSimConfig(int subId, @UiccAppType int apptype) { 250 mEapConfigs.put(EapMethodConfig.EAP_TYPE_SIM, new EapSimConfig(subId, apptype)); 251 return this; 252 } 253 254 /** 255 * Sets the configuration for EAP AKA. 256 * 257 * @param subId int the client's subId to be authenticated. 258 * @param apptype the {@link UiccAppType} apptype to be used for authentication. 259 * @return Builder this, to facilitate chaining. 260 */ 261 @NonNull setEapAkaConfig(int subId, @UiccAppType int apptype)262 public Builder setEapAkaConfig(int subId, @UiccAppType int apptype) { 263 mEapConfigs.put(EapMethodConfig.EAP_TYPE_AKA, new EapAkaConfig(subId, apptype)); 264 return this; 265 } 266 267 /** 268 * Sets the configuration for EAP AKA'. 269 * 270 * @param subId int the client's subId to be authenticated. 271 * @param apptype the {@link UiccAppType} apptype to be used for authentication. 272 * @param networkName String the network name to be used for authentication. 273 * @param allowMismatchedNetworkNames indicates whether the EAP library can ignore potential 274 * mismatches between the given network name and that received in an EAP-AKA' session. 275 * If false, mismatched network names will be handled as an Authentication Reject 276 * message. 277 * @return Builder this, to facilitate chaining. 278 */ 279 @NonNull setEapAkaPrimeConfig( int subId, @UiccAppType int apptype, @NonNull String networkName, boolean allowMismatchedNetworkNames)280 public Builder setEapAkaPrimeConfig( 281 int subId, 282 @UiccAppType int apptype, 283 @NonNull String networkName, 284 boolean allowMismatchedNetworkNames) { 285 mEapConfigs.put( 286 EapMethodConfig.EAP_TYPE_AKA_PRIME, 287 new EapAkaPrimeConfig( 288 subId, apptype, networkName, allowMismatchedNetworkNames)); 289 return this; 290 } 291 292 /** 293 * Sets the configuration for EAP MSCHAPv2. 294 * 295 * @param username String the client account's username to be authenticated. 296 * @param password String the client account's password to be authenticated. 297 * @return Builder this, to faciliate chaining. 298 */ 299 @NonNull setEapMsChapV2Config(@onNull String username, @NonNull String password)300 public Builder setEapMsChapV2Config(@NonNull String username, @NonNull String password) { 301 mEapConfigs.put( 302 EapMethodConfig.EAP_TYPE_MSCHAP_V2, new EapMsChapV2Config(username, password)); 303 return this; 304 } 305 306 /** 307 * Sets the configuration for EAP-TTLS. 308 * 309 * <p>Tunneled EAP-TTLS authentications are disallowed, as running multiple layers of 310 * EAP-TTLS increases the data footprint but has no discernible benefits over a single 311 * EAP-TTLS session with a non EAP-TTLS method nested inside it. 312 * 313 * @param serverCaCert the CA certificate for validating the received server certificate(s). 314 * If a certificate is provided, it MUST be the root CA used by the server, or 315 * authentication will fail. If no certificate is provided, any root CA in the system's 316 * truststore is considered acceptable. 317 * @param innerEapSessionConfig represents the configuration for the inner EAP instance 318 * @return Builder this, to facilitate chaining 319 */ 320 @NonNull setEapTtlsConfig( @ullable X509Certificate serverCaCert, @NonNull EapSessionConfig innerEapSessionConfig)321 public Builder setEapTtlsConfig( 322 @Nullable X509Certificate serverCaCert, 323 @NonNull EapSessionConfig innerEapSessionConfig) { 324 mEapConfigs.put( 325 EapMethodConfig.EAP_TYPE_TTLS, 326 new EapTtlsConfig(serverCaCert, innerEapSessionConfig)); 327 return this; 328 } 329 330 /** 331 * Adds an EAP method configuration. Internal use only. 332 * 333 * <p>This method will override the previously set configuration with the same method type. 334 * 335 * @hide 336 */ 337 @NonNull addEapMethodConfig(@onNull EapMethodConfig config)338 public Builder addEapMethodConfig(@NonNull EapMethodConfig config) { 339 Objects.requireNonNull(config, "EapMethodConfig is null"); 340 mEapConfigs.put(config.mMethodType, config); 341 return this; 342 } 343 344 /** 345 * Constructs and returns an EapSessionConfig with the configurations applied to this 346 * Builder. 347 * 348 * @return the EapSessionConfig constructed by this Builder. 349 */ 350 @NonNull build()351 public EapSessionConfig build() { 352 if (mEapConfigs.isEmpty()) { 353 throw new IllegalStateException("Must have at least one EAP method configured"); 354 } 355 356 return new EapSessionConfig(mEapConfigs, mEapIdentity); 357 } 358 } 359 360 /** EapMethodConfig represents a generic EAP method configuration. */ 361 public abstract static class EapMethodConfig { 362 private static final String METHOD_TYPE = "methodType"; 363 364 /** @hide */ 365 @Retention(RetentionPolicy.SOURCE) 366 @IntDef({EAP_TYPE_SIM, EAP_TYPE_TTLS, EAP_TYPE_AKA, EAP_TYPE_MSCHAP_V2, EAP_TYPE_AKA_PRIME}) 367 public @interface EapMethod {} 368 369 // EAP Type values defined by IANA 370 // @see https://www.iana.org/assignments/eap-numbers/eap-numbers.xhtml 371 /** 372 * EAP-Type value for the EAP-SIM method. 373 * 374 * <p>To include EAP-SIM as an authentication method, see {@link 375 * EapSessionConfig.Builder#setEapSimConfig(int, int)}. 376 * 377 * @see <a href="https://tools.ietf.org/html/rfc4186">RFC 4186, Extensible Authentication 378 * Protocol Method for Global System for Mobile Communications (GSM) Subscriber Identity 379 * Modules (EAP-SIM)</a> 380 */ 381 public static final int EAP_TYPE_SIM = 18; 382 383 /** 384 * EAP-Type value for the EAP-TTLS method. 385 * 386 * <p>To include EAP-TTLS as an authentication method, see {@link 387 * EapSessionConfig.Builder#setEapTtlsConfig(X509Certificate, EapSessionConfig)}. 388 * 389 * @see <a href="https://tools.ietf.org/html/rfc5281">RFC 5281, Extensible Authentication 390 * Protocol Tunneled Transport Layer Security Authenticated Protocol Version 0 391 * (EAP-TTLSv0)</a> 392 */ 393 public static final int EAP_TYPE_TTLS = 21; 394 395 /** 396 * EAP-Type value for the EAP-AKA method. 397 * 398 * <p>To include EAP-AKA as an authentication method, see {@link 399 * EapSessionConfig.Builder#setEapAkaConfig(int, int)}. 400 * 401 * @see <a href="https://tools.ietf.org/html/rfc4187">RFC 4187, Extensible Authentication 402 * Protocol Method for 3rd Generation Authentication and Key Agreement (EAP-AKA)</a> 403 */ 404 public static final int EAP_TYPE_AKA = 23; 405 406 /** 407 * EAP-Type value for the EAP-MS-CHAPv2 method. 408 * 409 * <p>To include EAP-MS-CHAPv2 as an authentication method, see {@link 410 * EapSessionConfig.Builder#setEapMsChapV2Config(String, String)}. 411 * 412 * @see <a href="https://tools.ietf.org/html/draft-kamath-pppext-eap-mschapv2-02">Microsoft 413 * EAP CHAP Extensions Draft (EAP MSCHAPv2)</a> 414 */ 415 public static final int EAP_TYPE_MSCHAP_V2 = 26; 416 417 /** 418 * EAP-Type value for the EAP-AKA' method. 419 * 420 * <p>To include EAP-AKA' as an authentication method, see {@link 421 * EapSessionConfig.Builder#setEapAkaPrimeConfig(int, int, String, boolean)}. 422 * 423 * @see <a href="https://tools.ietf.org/html/rfc5448">RFC 5448, Improved Extensible 424 * Authentication Protocol Method for 3rd Generation Authentication and Key Agreement 425 * (EAP-AKA')</a> 426 */ 427 public static final int EAP_TYPE_AKA_PRIME = 50; 428 429 @EapMethod private final int mMethodType; 430 431 /** @hide */ EapMethodConfig(@apMethod int methodType)432 EapMethodConfig(@EapMethod int methodType) { 433 mMethodType = methodType; 434 } 435 436 /** 437 * Constructs this object by deserializing a PersistableBundle 438 * 439 * @hide 440 */ 441 @NonNull fromPersistableBundle(PersistableBundle in)442 public static EapMethodConfig fromPersistableBundle(PersistableBundle in) { 443 Objects.requireNonNull(in, "PersistableBundle is null"); 444 445 int methodType = in.getInt(METHOD_TYPE); 446 switch (methodType) { 447 case EAP_TYPE_SIM: 448 return EapSimConfig.fromPersistableBundle(in); 449 case EAP_TYPE_AKA: 450 return EapAkaConfig.fromPersistableBundle(in); 451 case EAP_TYPE_AKA_PRIME: 452 return EapAkaPrimeConfig.fromPersistableBundle(in); 453 case EAP_TYPE_MSCHAP_V2: 454 return EapMsChapV2Config.fromPersistableBundle(in); 455 case EAP_TYPE_TTLS: 456 return EapTtlsConfig.fromPersistableBundle(in); 457 default: 458 throw new IllegalArgumentException("Invalid EAP Type: " + methodType); 459 } 460 } 461 462 /** 463 * Serializes this object to a PersistableBundle 464 * 465 * @hide 466 */ 467 @NonNull toPersistableBundle()468 protected PersistableBundle toPersistableBundle() { 469 final PersistableBundle result = new PersistableBundle(); 470 result.putInt(METHOD_TYPE, mMethodType); 471 return result; 472 } 473 474 /** 475 * Retrieves the EAP method type 476 * 477 * @return the IANA-defined EAP method constant 478 */ getMethodType()479 public int getMethodType() { 480 return mMethodType; 481 } 482 483 /** 484 * Check if this is EAP-only safe method. 485 * 486 * @return whether the method is EAP-only safe 487 * 488 * @see <a href="https://tools.ietf.org/html/rfc5998">RFC 5998#section 4, for safe eap 489 * methods</a> 490 * 491 * @hide 492 */ isEapOnlySafeMethod()493 public boolean isEapOnlySafeMethod() { 494 return false; 495 } 496 497 /** @hide */ 498 @Override hashCode()499 public int hashCode() { 500 return Objects.hash(mMethodType); 501 } 502 503 /** @hide */ 504 @Override equals(Object o)505 public boolean equals(Object o) { 506 if (!(o instanceof EapMethodConfig)) { 507 return false; 508 } 509 510 return mMethodType == ((EapMethodConfig) o).mMethodType; 511 } 512 } 513 514 /** 515 * EapUiccConfig represents the configs needed for EAP methods that rely on UICC cards for 516 * authentication. 517 * 518 * @hide 519 * @deprecated This class is not useful. Callers should only use its two subclasses {@link 520 * EapSimConfig} and {@link EapAkaConfig} 521 */ 522 @Deprecated 523 @SystemApi 524 public abstract static class EapUiccConfig extends EapMethodConfig { 525 /** @hide */ 526 protected static final String SUB_ID_KEY = "subId"; 527 /** @hide */ 528 protected static final String APP_TYPE_KEY = "apptype"; 529 530 private final int mSubId; 531 private final int mApptype; 532 EapUiccConfig(@apMethod int methodType, int subId, @UiccAppType int apptype)533 private EapUiccConfig(@EapMethod int methodType, int subId, @UiccAppType int apptype) { 534 super(methodType); 535 mSubId = subId; 536 mApptype = apptype; 537 } 538 539 /** 540 * Serializes this object to a PersistableBundle 541 * 542 * @hide 543 */ 544 @Override 545 @NonNull toPersistableBundle()546 protected PersistableBundle toPersistableBundle() { 547 final PersistableBundle result = super.toPersistableBundle(); 548 result.putInt(SUB_ID_KEY, mSubId); 549 result.putInt(APP_TYPE_KEY, mApptype); 550 551 return result; 552 } 553 554 /** 555 * Retrieves the subId 556 * 557 * @return the subId 558 */ getSubId()559 public int getSubId() { 560 return mSubId; 561 } 562 563 /** 564 * Retrieves the UICC app type 565 * 566 * @return the {@link UiccAppType} constant 567 */ getAppType()568 public int getAppType() { 569 return mApptype; 570 } 571 572 /** @hide */ 573 @Override isEapOnlySafeMethod()574 public boolean isEapOnlySafeMethod() { 575 return true; 576 } 577 578 /** @hide */ 579 @Override hashCode()580 public int hashCode() { 581 return Objects.hash(super.hashCode(), mSubId, mApptype); 582 } 583 584 /** @hide */ 585 @Override equals(Object o)586 public boolean equals(Object o) { 587 if (!super.equals(o) || !(o instanceof EapUiccConfig)) { 588 return false; 589 } 590 591 EapUiccConfig other = (EapUiccConfig) o; 592 593 return mSubId == other.mSubId && mApptype == other.mApptype; 594 } 595 } 596 597 /** 598 * EapSimConfig represents the configs needed for an EAP SIM session. 599 */ 600 public static class EapSimConfig extends EapUiccConfig { 601 /** @hide */ 602 @VisibleForTesting EapSimConfig(int subId, @UiccAppType int apptype)603 public EapSimConfig(int subId, @UiccAppType int apptype) { 604 super(EAP_TYPE_SIM, subId, apptype); 605 } 606 607 /** 608 * Constructs this object by deserializing a PersistableBundle 609 * 610 * @hide 611 */ 612 @NonNull fromPersistableBundle(@onNull PersistableBundle in)613 public static EapSimConfig fromPersistableBundle(@NonNull PersistableBundle in) { 614 Objects.requireNonNull(in, "PersistableBundle is null"); 615 return new EapSimConfig(in.getInt(SUB_ID_KEY), in.getInt(APP_TYPE_KEY)); 616 } 617 } 618 619 /** 620 * EapAkaConfig represents the configs needed for an EAP AKA session. 621 */ 622 public static class EapAkaConfig extends EapUiccConfig { 623 /** @hide */ 624 @VisibleForTesting EapAkaConfig(int subId, @UiccAppType int apptype)625 public EapAkaConfig(int subId, @UiccAppType int apptype) { 626 this(EAP_TYPE_AKA, subId, apptype); 627 } 628 629 /** @hide */ EapAkaConfig(int methodType, int subId, @UiccAppType int apptype)630 EapAkaConfig(int methodType, int subId, @UiccAppType int apptype) { 631 super(methodType, subId, apptype); 632 } 633 634 /** 635 * Constructs this object by deserializing a PersistableBundle 636 * 637 * @hide 638 */ 639 @NonNull fromPersistableBundle(@onNull PersistableBundle in)640 public static EapAkaConfig fromPersistableBundle(@NonNull PersistableBundle in) { 641 Objects.requireNonNull(in, "PersistableBundle is null"); 642 return new EapAkaConfig(in.getInt(SUB_ID_KEY), in.getInt(APP_TYPE_KEY)); 643 } 644 } 645 646 /** 647 * EapAkaPrimeConfig represents the configs needed for an EAP-AKA' session. 648 */ 649 public static class EapAkaPrimeConfig extends EapAkaConfig { 650 private static final String NETWORK_NAME_KEY = "networkName"; 651 private static final String ALL_MISMATCHED_NETWORK_KEY = "allowMismatchedNetworkNames"; 652 653 @NonNull private final String mNetworkName; 654 private final boolean mAllowMismatchedNetworkNames; 655 656 /** @hide */ 657 @VisibleForTesting EapAkaPrimeConfig( int subId, @UiccAppType int apptype, @NonNull String networkName, boolean allowMismatchedNetworkNames)658 public EapAkaPrimeConfig( 659 int subId, 660 @UiccAppType int apptype, 661 @NonNull String networkName, 662 boolean allowMismatchedNetworkNames) { 663 super(EAP_TYPE_AKA_PRIME, subId, apptype); 664 665 Objects.requireNonNull(networkName, "networkName must not be null"); 666 667 mNetworkName = networkName; 668 mAllowMismatchedNetworkNames = allowMismatchedNetworkNames; 669 } 670 671 /** 672 * Constructs this object by deserializing a PersistableBundle 673 * 674 * @hide 675 */ 676 @NonNull fromPersistableBundle(@onNull PersistableBundle in)677 public static EapAkaPrimeConfig fromPersistableBundle(@NonNull PersistableBundle in) { 678 Objects.requireNonNull(in, "PersistableBundle is null"); 679 return new EapAkaPrimeConfig( 680 in.getInt(SUB_ID_KEY), 681 in.getInt(APP_TYPE_KEY), 682 in.getString(NETWORK_NAME_KEY), 683 in.getBoolean(ALL_MISMATCHED_NETWORK_KEY)); 684 } 685 686 /** 687 * Serializes this object to a PersistableBundle 688 * 689 * @hide 690 */ 691 @Override 692 @NonNull toPersistableBundle()693 protected PersistableBundle toPersistableBundle() { 694 final PersistableBundle result = super.toPersistableBundle(); 695 result.putString(NETWORK_NAME_KEY, mNetworkName); 696 result.putBoolean(ALL_MISMATCHED_NETWORK_KEY, mAllowMismatchedNetworkNames); 697 698 return result; 699 } 700 701 /** 702 * Retrieves the UICC app type 703 * 704 * @return the {@link UiccAppType} constant 705 */ 706 @NonNull getNetworkName()707 public String getNetworkName() { 708 return mNetworkName; 709 } 710 711 /** 712 * Checks if mismatched network names are allowed 713 * 714 * @return whether network name mismatches are allowed 715 */ allowsMismatchedNetworkNames()716 public boolean allowsMismatchedNetworkNames() { 717 return mAllowMismatchedNetworkNames; 718 } 719 720 /** @hide */ 721 @Override hashCode()722 public int hashCode() { 723 return Objects.hash(super.hashCode(), mNetworkName, mAllowMismatchedNetworkNames); 724 } 725 726 /** @hide */ 727 @Override equals(Object o)728 public boolean equals(Object o) { 729 if (!super.equals(o) || !(o instanceof EapAkaPrimeConfig)) { 730 return false; 731 } 732 733 EapAkaPrimeConfig other = (EapAkaPrimeConfig) o; 734 735 return mNetworkName.equals(other.mNetworkName) 736 && mAllowMismatchedNetworkNames == other.mAllowMismatchedNetworkNames; 737 } 738 } 739 740 /** 741 * EapMsChapV2Config represents the configs needed for an EAP MSCHAPv2 session. 742 */ 743 public static class EapMsChapV2Config extends EapMethodConfig { 744 private static final String USERNAME_KEY = "username"; 745 private static final String PASSWORD_KEY = "password"; 746 747 @NonNull private final String mUsername; 748 @NonNull private final String mPassword; 749 750 /** @hide */ 751 @VisibleForTesting EapMsChapV2Config(String username, String password)752 public EapMsChapV2Config(String username, String password) { 753 super(EAP_TYPE_MSCHAP_V2); 754 755 Objects.requireNonNull(username, "username must not be null"); 756 Objects.requireNonNull(password, "password must not be null"); 757 758 mUsername = username; 759 mPassword = password; 760 } 761 762 /** 763 * Constructs this object by deserializing a PersistableBundle 764 * 765 * @hide 766 */ 767 @NonNull fromPersistableBundle(@onNull PersistableBundle in)768 public static EapMsChapV2Config fromPersistableBundle(@NonNull PersistableBundle in) { 769 Objects.requireNonNull(in, "PersistableBundle is null"); 770 return new EapMsChapV2Config(in.getString(USERNAME_KEY), in.getString(PASSWORD_KEY)); 771 } 772 773 /** 774 * Serializes this object to a PersistableBundle 775 * 776 * @hide 777 */ 778 @Override 779 @NonNull toPersistableBundle()780 protected PersistableBundle toPersistableBundle() { 781 final PersistableBundle result = super.toPersistableBundle(); 782 result.putString(USERNAME_KEY, mUsername); 783 result.putString(PASSWORD_KEY, mPassword); 784 785 return result; 786 } 787 788 /** 789 * Retrieves the username 790 * 791 * @return the username to be used by MSCHAPV2 792 */ 793 @NonNull getUsername()794 public String getUsername() { 795 return mUsername; 796 } 797 798 /** 799 * Retrieves the password 800 * 801 * @return the password to be used by MSCHAPV2 802 */ 803 @NonNull getPassword()804 public String getPassword() { 805 return mPassword; 806 } 807 808 /** @hide */ 809 @Override hashCode()810 public int hashCode() { 811 return Objects.hash(super.hashCode(), mUsername, mPassword); 812 } 813 814 /** @hide */ 815 @Override equals(Object o)816 public boolean equals(Object o) { 817 if (!super.equals(o) || !(o instanceof EapMsChapV2Config)) { 818 return false; 819 } 820 821 EapMsChapV2Config other = (EapMsChapV2Config) o; 822 823 return mUsername.equals(other.mUsername) && mPassword.equals(other.mPassword); 824 } 825 } 826 827 /** 828 * EapTtlsConfig represents the configs needed for an EAP-TTLS session. 829 */ 830 public static class EapTtlsConfig extends EapMethodConfig { 831 private static final String TRUST_CERT_KEY = "TRUST_CERT_KEY"; 832 private static final String EAP_SESSION_CONFIG_KEY = "EAP_SESSION_CONFIG_KEY"; 833 834 @Nullable private final TrustAnchor mOverrideTrustAnchor; 835 @NonNull private final EapSessionConfig mInnerEapSessionConfig; 836 837 /** @hide */ 838 @VisibleForTesting EapTtlsConfig( @ullable X509Certificate serverCaCert, @NonNull EapSessionConfig innerEapSessionConfig)839 public EapTtlsConfig( 840 @Nullable X509Certificate serverCaCert, 841 @NonNull EapSessionConfig innerEapSessionConfig) { 842 super(EAP_TYPE_TTLS); 843 mInnerEapSessionConfig = 844 Objects.requireNonNull( 845 innerEapSessionConfig, "innerEapSessionConfig must not be null"); 846 if (mInnerEapSessionConfig.getEapConfigs().containsKey(EAP_TYPE_TTLS)) { 847 throw new IllegalArgumentException("Recursive EAP-TTLS method configs not allowed"); 848 } 849 850 mOverrideTrustAnchor = 851 (serverCaCert == null) 852 ? null 853 : new TrustAnchor(serverCaCert, null /* nameConstraints */); 854 } 855 856 /** 857 * Constructs this object by deserializing a PersistableBundle. 858 * 859 * @hide 860 */ 861 @NonNull fromPersistableBundle(@onNull PersistableBundle in)862 public static EapTtlsConfig fromPersistableBundle(@NonNull PersistableBundle in) { 863 Objects.requireNonNull(in, "PersistableBundle is null"); 864 865 PersistableBundle trustCertBundle = in.getPersistableBundle(TRUST_CERT_KEY); 866 X509Certificate caCert = null; 867 if (trustCertBundle != null) { 868 byte[] encodedCert = PersistableBundleUtils.toByteArray(trustCertBundle); 869 caCert = IkeCertUtils.certificateFromByteArray(encodedCert); 870 } 871 872 PersistableBundle eapSessionConfigBundle = 873 in.getPersistableBundle(EAP_SESSION_CONFIG_KEY); 874 Objects.requireNonNull(eapSessionConfigBundle, "eapSessionConfigBundle is null"); 875 EapSessionConfig eapSessionConfig = 876 EapSessionConfig.fromPersistableBundle(eapSessionConfigBundle); 877 878 return new EapTtlsConfig(caCert, eapSessionConfig); 879 } 880 881 /** 882 * Serializes this object to a PersistableBundle. 883 * 884 * @hide 885 */ 886 @Override 887 @NonNull toPersistableBundle()888 protected PersistableBundle toPersistableBundle() { 889 final PersistableBundle result = super.toPersistableBundle(); 890 891 try { 892 if (mOverrideTrustAnchor != null) { 893 result.putPersistableBundle( 894 TRUST_CERT_KEY, 895 PersistableBundleUtils.fromByteArray( 896 mOverrideTrustAnchor.getTrustedCert().getEncoded())); 897 } 898 899 result.putPersistableBundle( 900 EAP_SESSION_CONFIG_KEY, mInnerEapSessionConfig.toPersistableBundle()); 901 } catch (CertificateEncodingException e) { 902 throw new IllegalArgumentException("Fail to encode the certificate"); 903 } 904 905 return result; 906 } 907 908 /** @hide */ 909 @Override isEapOnlySafeMethod()910 public boolean isEapOnlySafeMethod() { 911 return true; 912 } 913 914 /** 915 * Retrieves the provided CA certificate for validating the remote certificate(s) 916 * 917 * @return the CA certificate for validating the received server certificate or null if the 918 * system default is preferred 919 */ 920 @Nullable getServerCaCert()921 public X509Certificate getServerCaCert() { 922 return (mOverrideTrustAnchor == null) ? null : mOverrideTrustAnchor.getTrustedCert(); 923 } 924 925 /** 926 * Retrieves the inner EAP session config 927 * 928 * @return an EapSessionConfig representing the config for tunneled EAP authentication 929 */ 930 @NonNull getInnerEapSessionConfig()931 public EapSessionConfig getInnerEapSessionConfig() { 932 return mInnerEapSessionConfig; 933 } 934 935 /** @hide */ 936 @Override hashCode()937 public int hashCode() { 938 // Use #getTrustedCert() because TrustAnchor does not override #hashCode() 939 940 return Objects.hash( 941 super.hashCode(), 942 mInnerEapSessionConfig, 943 (mOverrideTrustAnchor == null) ? null : mOverrideTrustAnchor.getTrustedCert()); 944 } 945 946 /** @hide */ 947 @Override equals(Object o)948 public boolean equals(Object o) { 949 if (!super.equals(o) || !(o instanceof EapTtlsConfig)) { 950 return false; 951 } 952 953 EapTtlsConfig other = (EapTtlsConfig) o; 954 955 if (!Objects.equals(mInnerEapSessionConfig, other.mInnerEapSessionConfig)) { 956 return false; 957 } 958 959 if (mOverrideTrustAnchor == null && other.mOverrideTrustAnchor == null) { 960 return true; 961 } 962 963 return mOverrideTrustAnchor != null 964 && other.mOverrideTrustAnchor != null 965 && Objects.equals( 966 mOverrideTrustAnchor.getTrustedCert(), 967 other.mOverrideTrustAnchor.getTrustedCert()); 968 } 969 } 970 971 /** 972 * Checks if all the methods in the session are EAP-only safe 973 * 974 * @return whether all the methods in the session are EAP-only safe 975 * 976 * @see <a href="https://tools.ietf.org/html/rfc5998">RFC 5998#section 4, for safe eap 977 * methods</a> 978 * 979 * @hide 980 */ areAllMethodsEapOnlySafe()981 public boolean areAllMethodsEapOnlySafe() { 982 for (Map.Entry<Integer, EapMethodConfig> eapConfigsEntry : mEapConfigs.entrySet()) { 983 if (!eapConfigsEntry.getValue().isEapOnlySafeMethod()) { 984 return false; 985 } 986 } 987 988 return true; 989 } 990 } 991