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