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