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 static com.android.internal.net.eap.message.EapData.EAP_TYPE_AKA; 20 import static com.android.internal.net.eap.message.EapData.EAP_TYPE_AKA_PRIME; 21 import static com.android.internal.net.eap.message.EapData.EAP_TYPE_MSCHAP_V2; 22 import static com.android.internal.net.eap.message.EapData.EAP_TYPE_SIM; 23 import static com.android.internal.net.eap.message.EapData.EAP_TYPE_TTLS; 24 25 import android.annotation.NonNull; 26 import android.annotation.Nullable; 27 import android.annotation.SystemApi; 28 import android.telephony.Annotation.UiccAppType; 29 30 import com.android.internal.annotations.VisibleForTesting; 31 import com.android.internal.net.eap.message.EapData.EapMethod; 32 33 import java.util.Collections; 34 import java.util.HashMap; 35 import java.util.Map; 36 37 /** 38 * EapSessionConfig represents a container for EAP method configuration. 39 * 40 * <p>The EAP authentication server decides which EAP method is used, so clients are encouraged to 41 * provide configs for several EAP methods. 42 * 43 * @hide 44 */ 45 @SystemApi 46 public final class EapSessionConfig { 47 /** @hide */ 48 @VisibleForTesting static final byte[] DEFAULT_IDENTITY = new byte[0]; 49 50 // IANA -> EapMethodConfig for that method 51 /** @hide */ 52 public final Map<Integer, EapMethodConfig> eapConfigs; 53 /** @hide */ 54 public final byte[] eapIdentity; 55 56 /** @hide */ 57 @VisibleForTesting EapSessionConfig(Map<Integer, EapMethodConfig> eapConfigs, byte[] eapIdentity)58 public EapSessionConfig(Map<Integer, EapMethodConfig> eapConfigs, byte[] eapIdentity) { 59 this.eapConfigs = Collections.unmodifiableMap(eapConfigs); 60 this.eapIdentity = eapIdentity; 61 } 62 63 /** Retrieves client's EAP Identity */ 64 @NonNull getEapIdentity()65 public byte[] getEapIdentity() { 66 return eapIdentity; 67 } 68 69 /** 70 * Retrieves configuration for EAP SIM 71 * 72 * @return the configuration for EAP SIM, or null if it was not set 73 */ 74 @Nullable getEapSimConfig()75 public EapSimConfig getEapSimConfig() { 76 return (EapSimConfig) eapConfigs.get(EAP_TYPE_SIM); 77 } 78 79 /** 80 * Retrieves configuration for EAP AKA 81 * 82 * @return the configuration for EAP AKA, or null if it was not set 83 */ 84 @Nullable getEapAkaConfig()85 public EapAkaConfig getEapAkaConfig() { 86 return (EapAkaConfig) eapConfigs.get(EAP_TYPE_AKA); 87 } 88 89 /** 90 * Retrieves configuration for EAP AKA' 91 * 92 * @return the configuration for EAP AKA', or null if it was not set 93 */ 94 @Nullable getEapAkaPrimeConfig()95 public EapAkaPrimeConfig getEapAkaPrimeConfig() { 96 return (EapAkaPrimeConfig) eapConfigs.get(EAP_TYPE_AKA_PRIME); 97 } 98 99 /** 100 * Retrieves configuration for EAP MSCHAPV2 101 * 102 * @return the configuration for EAP MSCHAPV2, or null if it was not set 103 */ 104 @Nullable getEapMsChapV2onfig()105 public EapMsChapV2Config getEapMsChapV2onfig() { 106 return (EapMsChapV2Config) eapConfigs.get(EAP_TYPE_MSCHAP_V2); 107 } 108 109 /** 110 * Retrieves configuration for EAP-TTLS 111 * 112 * @return the configuration for EAP-TTLS, or null if it was not set 113 * @hide 114 */ 115 @Nullable getEapTtlsConfig()116 public EapTtlsConfig getEapTtlsConfig() { 117 return (EapTtlsConfig) eapConfigs.get(EAP_TYPE_TTLS); 118 } 119 120 /** This class can be used to incrementally construct an {@link EapSessionConfig}. */ 121 public static final class Builder { 122 private final Map<Integer, EapMethodConfig> mEapConfigs; 123 private byte[] mEapIdentity; 124 125 /** Constructs and returns a new Builder for constructing an {@link EapSessionConfig}. */ Builder()126 public Builder() { 127 mEapConfigs = new HashMap<>(); 128 mEapIdentity = DEFAULT_IDENTITY; 129 } 130 131 /** 132 * Sets the client's EAP Identity. 133 * 134 * @param eapIdentity byte[] representing the client's EAP Identity. 135 * @return Builder this, to facilitate chaining. 136 */ 137 @NonNull setEapIdentity(@onNull byte[] eapIdentity)138 public Builder setEapIdentity(@NonNull byte[] eapIdentity) { 139 this.mEapIdentity = eapIdentity.clone(); 140 return this; 141 } 142 143 /** 144 * Sets the configuration for EAP SIM. 145 * 146 * @param subId int the client's subId to be authenticated. 147 * @param apptype the {@link UiccAppType} apptype to be used for authentication. 148 * @return Builder this, to facilitate chaining. 149 */ 150 @NonNull setEapSimConfig(int subId, @UiccAppType int apptype)151 public Builder setEapSimConfig(int subId, @UiccAppType int apptype) { 152 mEapConfigs.put(EAP_TYPE_SIM, new EapSimConfig(subId, apptype)); 153 return this; 154 } 155 156 /** 157 * Sets the configuration for EAP AKA. 158 * 159 * @param subId int the client's subId to be authenticated. 160 * @param apptype the {@link UiccAppType} apptype to be used for authentication. 161 * @return Builder this, to facilitate chaining. 162 */ 163 @NonNull setEapAkaConfig(int subId, @UiccAppType int apptype)164 public Builder setEapAkaConfig(int subId, @UiccAppType int apptype) { 165 mEapConfigs.put(EAP_TYPE_AKA, new EapAkaConfig(subId, apptype)); 166 return this; 167 } 168 169 /** 170 * Sets the configuration for EAP AKA'. 171 * 172 * @param subId int the client's subId to be authenticated. 173 * @param apptype the {@link UiccAppType} apptype to be used for authentication. 174 * @param networkName String the network name to be used for authentication. 175 * @param allowMismatchedNetworkNames indicates whether the EAP library can ignore potential 176 * mismatches between the given network name and that received in an EAP-AKA' session. 177 * If false, mismatched network names will be handled as an Authentication Reject 178 * message. 179 * @return Builder this, to facilitate chaining. 180 */ 181 @NonNull setEapAkaPrimeConfig( int subId, @UiccAppType int apptype, @NonNull String networkName, boolean allowMismatchedNetworkNames)182 public Builder setEapAkaPrimeConfig( 183 int subId, 184 @UiccAppType int apptype, 185 @NonNull String networkName, 186 boolean allowMismatchedNetworkNames) { 187 mEapConfigs.put( 188 EAP_TYPE_AKA_PRIME, 189 new EapAkaPrimeConfig( 190 subId, apptype, networkName, allowMismatchedNetworkNames)); 191 return this; 192 } 193 194 /** 195 * Sets the configuration for EAP MSCHAPv2. 196 * 197 * @param username String the client account's username to be authenticated. 198 * @param password String the client account's password to be authenticated. 199 * @return Builder this, to faciliate chaining. 200 */ 201 @NonNull setEapMsChapV2Config(@onNull String username, @NonNull String password)202 public Builder setEapMsChapV2Config(@NonNull String username, @NonNull String password) { 203 mEapConfigs.put(EAP_TYPE_MSCHAP_V2, new EapMsChapV2Config(username, password)); 204 return this; 205 } 206 207 /** 208 * Sets the configuration for EAP-TTLS 209 * 210 * @return Builder this, to facilitate chaining 211 * @hide 212 */ 213 @NonNull setEapTtlsConfig()214 public Builder setEapTtlsConfig() { 215 mEapConfigs.put(EAP_TYPE_TTLS, new EapTtlsConfig()); 216 return this; 217 } 218 219 /** 220 * Constructs and returns an EapSessionConfig with the configurations applied to this 221 * Builder. 222 * 223 * @return the EapSessionConfig constructed by this Builder. 224 */ 225 @NonNull build()226 public EapSessionConfig build() { 227 if (mEapConfigs.isEmpty()) { 228 throw new IllegalStateException("Must have at least one EAP method configured"); 229 } 230 231 return new EapSessionConfig(mEapConfigs, mEapIdentity); 232 } 233 } 234 235 /** 236 * EapMethodConfig represents a generic EAP method configuration. 237 */ 238 public abstract static class EapMethodConfig { 239 /** @hide */ 240 @EapMethod public final int methodType; 241 242 /** @hide */ EapMethodConfig(@apMethod int methodType)243 EapMethodConfig(@EapMethod int methodType) { 244 this.methodType = methodType; 245 } 246 247 /** 248 * Retrieves the EAP method type 249 * 250 * @return the IANA-defined EAP method constant 251 */ getMethodType()252 public int getMethodType() { 253 return methodType; 254 } 255 256 /** 257 * Check if this is EAP-only safe method. 258 * 259 * @return whether the method is EAP-only safe 260 * 261 * @see <a href="https://tools.ietf.org/html/rfc5998">RFC 5998#section 4, for safe eap 262 * methods</a> 263 * 264 * @hide 265 */ isEapOnlySafeMethod()266 public boolean isEapOnlySafeMethod() { 267 return false; 268 } 269 } 270 271 /** 272 * EapUiccConfig represents the configs needed for EAP methods that rely on UICC cards for 273 * authentication. 274 */ 275 public abstract static class EapUiccConfig extends EapMethodConfig { 276 /** @hide */ 277 public final int subId; 278 /** @hide */ 279 public final int apptype; 280 EapUiccConfig(@apMethod int methodType, int subId, @UiccAppType int apptype)281 private EapUiccConfig(@EapMethod int methodType, int subId, @UiccAppType int apptype) { 282 super(methodType); 283 this.subId = subId; 284 this.apptype = apptype; 285 } 286 287 /** 288 * Retrieves the subId 289 * 290 * @return the subId 291 */ getSubId()292 public int getSubId() { 293 return subId; 294 } 295 296 /** 297 * Retrieves the UICC app type 298 * 299 * @return the {@link UiccAppType} constant 300 */ getAppType()301 public int getAppType() { 302 return apptype; 303 } 304 305 /** @hide */ 306 @Override isEapOnlySafeMethod()307 public boolean isEapOnlySafeMethod() { 308 return true; 309 } 310 } 311 312 /** 313 * EapSimConfig represents the configs needed for an EAP SIM session. 314 */ 315 public static class EapSimConfig extends EapUiccConfig { 316 /** @hide */ 317 @VisibleForTesting EapSimConfig(int subId, @UiccAppType int apptype)318 public EapSimConfig(int subId, @UiccAppType int apptype) { 319 super(EAP_TYPE_SIM, subId, apptype); 320 } 321 } 322 323 /** 324 * EapAkaConfig represents the configs needed for an EAP AKA session. 325 */ 326 public static class EapAkaConfig extends EapUiccConfig { 327 /** @hide */ 328 @VisibleForTesting EapAkaConfig(int subId, @UiccAppType int apptype)329 public EapAkaConfig(int subId, @UiccAppType int apptype) { 330 this(EAP_TYPE_AKA, subId, apptype); 331 } 332 333 /** @hide */ EapAkaConfig(int methodType, int subId, @UiccAppType int apptype)334 EapAkaConfig(int methodType, int subId, @UiccAppType int apptype) { 335 super(methodType, subId, apptype); 336 } 337 } 338 339 /** 340 * EapAkaPrimeConfig represents the configs needed for an EAP-AKA' session. 341 */ 342 public static class EapAkaPrimeConfig extends EapAkaConfig { 343 /** @hide */ 344 @NonNull public final String networkName; 345 /** @hide */ 346 public final boolean allowMismatchedNetworkNames; 347 348 /** @hide */ 349 @VisibleForTesting EapAkaPrimeConfig( int subId, @UiccAppType int apptype, @NonNull String networkName, boolean allowMismatchedNetworkNames)350 public EapAkaPrimeConfig( 351 int subId, 352 @UiccAppType int apptype, 353 @NonNull String networkName, 354 boolean allowMismatchedNetworkNames) { 355 super(EAP_TYPE_AKA_PRIME, subId, apptype); 356 357 if (networkName == null) { 358 throw new IllegalArgumentException("NetworkName was null"); 359 } 360 361 this.networkName = networkName; 362 this.allowMismatchedNetworkNames = allowMismatchedNetworkNames; 363 } 364 365 /** 366 * Retrieves the UICC app type 367 * 368 * @return the {@link UiccAppType} constant 369 */ 370 @NonNull getNetworkName()371 public String getNetworkName() { 372 return networkName; 373 } 374 375 /** 376 * Checks if mismatched network names are allowed 377 * 378 * @return whether network name mismatches are allowed 379 */ allowsMismatchedNetworkNames()380 public boolean allowsMismatchedNetworkNames() { 381 return allowMismatchedNetworkNames; 382 } 383 } 384 385 /** 386 * EapMsChapV2Config represents the configs needed for an EAP MSCHAPv2 session. 387 */ 388 public static class EapMsChapV2Config extends EapMethodConfig { 389 /** @hide */ 390 @NonNull public final String username; 391 /** @hide */ 392 @NonNull public final String password; 393 394 /** @hide */ 395 @VisibleForTesting EapMsChapV2Config(String username, String password)396 public EapMsChapV2Config(String username, String password) { 397 super(EAP_TYPE_MSCHAP_V2); 398 399 if (username == null || password == null) { 400 throw new IllegalArgumentException("Username or password was null"); 401 } 402 403 this.username = username; 404 this.password = password; 405 } 406 407 /** 408 * Retrieves the username 409 * 410 * @return the username to be used by MSCHAPV2 411 */ 412 @NonNull getUsername()413 public String getUsername() { 414 return username; 415 } 416 417 /** 418 * Retrieves the password 419 * 420 * @return the password to be used by MSCHAPV2 421 */ 422 @NonNull getPassword()423 public String getPassword() { 424 return password; 425 } 426 } 427 428 /** 429 * EapTtlsConfig represents the configs needed for an EAP-TTLS session. 430 * 431 * @hide 432 */ 433 public static class EapTtlsConfig extends EapMethodConfig { 434 435 /** @hide */ 436 @VisibleForTesting EapTtlsConfig()437 public EapTtlsConfig() { 438 super(EAP_TYPE_TTLS); 439 } 440 441 /** @hide */ 442 @Override isEapOnlySafeMethod()443 public boolean isEapOnlySafeMethod() { 444 return true; 445 } 446 } 447 448 /** 449 * Checks if all the methods in the session are EAP-only safe 450 * 451 * @return whether all the methods in the session are EAP-only safe 452 * 453 * @see <a href="https://tools.ietf.org/html/rfc5998">RFC 5998#section 4, for safe eap 454 * methods</a> 455 * 456 * @hide 457 */ areAllMethodsEapOnlySafe()458 public boolean areAllMethodsEapOnlySafe() { 459 for(Map.Entry<Integer, EapMethodConfig> eapConfigsEntry : eapConfigs.entrySet()) { 460 if (!eapConfigsEntry.getValue().isEapOnlySafeMethod()) { 461 return false; 462 } 463 } 464 465 return true; 466 } 467 } 468